Skip to content

feat(dv): pause the FEL curve fold where its RPU cannot reach the picture, add foldsDolbyVisionFEL (#1018) - #1019

Merged
superuser404notfound merged 5 commits into
mainfrom
feat/issue-1018-fel-fold-switch
Nov 10, 2026
Merged

superuser404notfound merged 5 commits into
mainfrom
feat/issue-1018-fel-fold-switch

Conversation

@superuser404notfound

Copy link
Copy Markdown
Owner

Answers #1018. Two parts, one switch and one automatic gate.

What was measured first

On an Apple TV 4K (3rd generation, tvOS 27.2) at an HDR10 television without Dolby Vision, with a Profile 8.1 clip whose RPU darkens every other 2 s block, paused screenshots against the unedited clip:

Panel Route RPU applied
SDR (Match Content off) media or master playlist yes
HDR10 (Match Dynamic Range on) master playlist no, the base layer bit for bit
HDR10 forceDolbyVisionOnNonDVDisplay (Profile 5) yes, unedited frames identical to the plain route

So dvModeAvailable is the wrong gate: a panel in SDR, the Profile 5 route and every Mac apply the RPU, and the fold works there. The fold is wasted only on tvOS, without Dolby Vision, off the Profile 5 route, while the panel presents HDR.

Changes

  • LoadOptions.foldsDolbyVisionFEL (default true): turns the fold off per load. A tuning field that reloadAtCurrentPosition(applying:) carries; ignored without the trait. The load logs [FelCurves] fold not armed: <reason>.
  • The fold gate: FelCurveLookahead re-reads a per-session verdict at every keyframe and, while it holds, passes packets through converted with the stream's mapping (no GOP held back, nothing decoded). Logged as [FelCurves] fold paused.
  • The panel answer: predicted at load (range matching on, HDR-eligible display, engine HDR criteria, no HDR master refused in this process), because the readout taken during the switch reads 1.00 on exactly these panels. An HDR master reaching readyToPlay sets it, a refused master clears it.

Device results (same Apple TV, P7 FEL source, 150 Mbit/s over the LAN, start at 2:00 plus 4 seeks, two runs each)

fold on fold off
HDR10, before the load-time prediction: first load 5.04 to 5.14 s 4.33 to 4.39 s
HDR10, with this PR: first load 4.33 to 4.42 s 4.35 to 4.37 s
HDR10, with this PR: seeks 4.39 to 4.43 s 4.37 to 4.45 s

On an SDR panel the fold stays armed, and with forceDolbyVisionOnNonDVDisplay it stays armed too (that is where it reaches the picture).

Tests: Issue1018FelFoldGateTests (gate truth table, load-time prediction, the lookahead holds nothing back while bypassed, on a real FEL clip when DV_FEL_TESTS_DIR is set). A /code-review low found a mid-GOP resume and stale docs, both fixed in cd5ba78.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SeT6NgMt1vv32kPBhUmsUz

Vincent Herbst and others added 4 commits November 10, 2026 21:02
…ture, add a per-load switch (#1018)

Measured on an Apple TV 4K (tvOS 27.2) at an HDR10 television: with the panel in HDR10, tvOS shows the
base layer bit for bit and ignores the RPU; a panel in SDR, the AE#455 Profile 5 route and a Mac apply it.
The lookahead now re-reads that verdict at every GOP boundary and passes packets through with the stream's
mapping while it holds, so such a display no longer pays the GOP hold-back and the per-scene decodes.

LoadOptions.foldsDolbyVisionFEL (default true) turns the fold off per load; the load logs why a
Profile 7 conversion runs without it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SeT6NgMt1vv32kPBhUmsUz
…presents HDR (#1018)

The load-time panel readout is taken mid-switch and reads 1.00 on the
Apple TV this was measured on, so the gate never closed. An HDR master
that reaches readyToPlay was accepted, which a display presenting SDR
refuses at parse time (AE#459).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SeT6NgMt1vv32kPBhUmsUz
…e will engage the panel (#1018)

Measured on the Apple TV the gate was built for: from a source over the
network the first load still paid ~0.7 s for the fold, because the first
producer reads during the display switch and the panel answer only arrives
at readyToPlay. With range matching on, an HDR-eligible display and an HDR
criteria write from the engine, the panel is taken as presenting HDR from
the start; a master the display refuses clears it on the session, and the
fold resumes at the next keyframe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SeT6NgMt1vv32kPBhUmsUz
…oad-time panel prediction (#1018)

Review findings: while paused the lookahead re-read the gate on every packet,
so a refused master could resume the fold mid-GOP; it now re-reads it at
keyframes only, as the log and the docs say. The docs still described the
gate as waiting for a proven panel, which the load-time prediction replaced.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SeT6NgMt1vv32kPBhUmsUz

@quint-aether quint-aether Bot 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.

Automated review

Status: 🟠 Needs changes. Real issues to fix before merge.

The PR adds LoadOptions.foldsDolbyVisionFEL and an automatic gate that pauses the FEL curve fold on a tvOS HDR10 panel without Dolby Vision, where the measurements show the RPU is ignored. The direction is right: the fix is in the engine, it is backed by a device measurement, and the plain conversion stays the fallback.

Findings

  • Should fix: Once FelCurveLookahead is folding, it never switches to pass-through during continuous playback. The gate is only re-read at a keyframe when buffered is empty, and that never happens while folding. So a session whose load-time prediction was SDR and that is later confirmed as HDR (readyToPlay of the HDR master, the #459 probe) keeps folding until a seek. The docs say a change "takes effect at the next keyframe in both directions". Nothing tests the change of direction either. (Sources/AetherEngine/Video/FelCurves/FelCurveLookahead.swift:110, docs/dolby-vision-fel.md:856)
  • Nit: hdrWriteExpectedToEngagePanel() is inserted between currentPanelIsHDR() and its doc comment. The old comment now sits on the new function, and currentPanelIsHDR() has none. (Sources/AetherEngine/Display/DisplayCriteriaController.swift:1373)
  • Nit: The same thing happens with felGatePanelPresentsHDR: the AE#459 doc of sessionPanelPresentsHDR now sits on the new function. (Sources/AetherEngine/AetherEngine+Probe.swift:1088)

Checklist: CHANGELOG yes, docs yes, tests yes (the gate truth tables and the start-in-bypass case; the switch during playback is not covered), traits both ways yes (the option is a plain field and the lookahead stays behind DolbyVisionFelCurves)

Needs a device run: whether the load-time prediction (hdrWriteExpectedToEngagePanel reads true for a rate-only matching setup) causes a short unfolded stretch on an SDR panel before the refused master clears it, and the start and seek timings on a display where the prediction is false but readyToPlay confirms HDR.

Thanks for measuring each panel and route before gating; the table makes the rule easy to check.

Automated review by Quint (Claude) of cd5ba78. It reads the code, it does not build or run it; a maintainer reviews and merges.

if isFolding == false || (!isVideo && buffered.isEmpty) {
return packet
}
if isVideo, buffered.isEmpty, packet.pointee.flags & AV_PKT_FLAG_KEY != 0 {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

While the lookahead is folding, buffered is never empty when a video keyframe arrives. It still holds the previous GOP, which line 117 releases only after this check. So updateBypass() cannot move a folding session into pass-through during continuous playback. It only does so at stream start, after reset() (a seek) or after a maxBufferedPackets release.

Scenario: the load-time prediction is false (host-owned criteria, matching off at load, or hdrWriteExpectedToEngagePanel() reads false). Then readyToPlay of the HDR master or republishPanelPresentsHDR sets the flag to true. The fold keeps holding back GOPs and decoding scenes until the viewer seeks. The other direction (pass-through back to folding) works, because buffered stays empty while bypassing.

Suggested shape: on a video keyframe, first release the held GOP if bufferedHasVideo, then call updateBypass(). If that enters pass-through, do not return packet directly, because ready now holds the released GOP and the keyframe would overtake it. Convert the keyframe, ready.append(packet) and continue instead. A test that drives foldIsUnseen from a toggling closure on the FEL clip would pin both directions.

Comment thread docs/dolby-vision-fel.md
| HDR10 (Match Dynamic Range on) | master playlist | no, the base layer bit for bit |
| HDR10 | `forceDolbyVisionOnNonDVDisplay` (Profile 5) | yes, no colour shift on the unedited frames |

A display that takes Dolby Vision and a Mac apply it as well. So the fold pauses in exactly one case: on tvOS, without Dolby Vision, off the Profile 5 route, while the panel presents HDR. The load predicts that from the start when range matching is on, the display can play HDR, the engine writes HDR criteria and no HDR master was refused in this process, because the readout taken during the display switch reads SDR on exactly these panels and the first producer would otherwise fold through the switch (measured: 0.7 s more to the first frame from a network source). An HDR master reaching readyToPlay confirms it; a refused master clears it. The check runs at every GOP keyframe. While it holds, packets pass through converted with the stream's mapping, no GOP is held back and nothing is decoded, and the log says `[FelCurves] fold paused`. A change of the answer during playback takes effect at the next keyframe in both directions.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

"A change of the answer during playback takes effect at the next keyframe in both directions" does not hold for folding to paused with the current lookahead (see the comment on FelCurveLookahead.swift:110). Fix the code, or narrow this sentence to say the pause takes effect at the next seek.

/// headroom above 1.0 answers it; a decayed one is answered by `panelPresentsHDR` from what this display
/// has already proven, because HDR video on the screen pulls the value down and a replay asks while the
/// previous session was still doing that.
/// AE#1018: whether an HDR criteria write is expected to put the panel in HDR, before the switch has

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nit: this doc block is inserted right after the existing /// lines that describe currentPanelIsHDR() ("headroom above 1.0 answers it ..."). Both now form one comment on hdrWriteExpectedToEngagePanel(), and currentPanelIsHDR() loses its doc. Move the new function above that comment block.

///
/// `nil` readout means suppressed, not false: the difference matters in the log, where a suppressed
/// session has nothing to compare the assertion against.
/// AE#1018: the panel answer the FEL fold gate starts a session with. The label alone arrives too late:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nit: same as in DisplayCriteriaController. The AE#459 doc of sessionPanelPresentsHDR (ending "nil readout means suppressed, not false ...") now runs into this comment and attaches to felGatePanelPresentsHDR, leaving sessionPanelPresentsHDR undocumented. Place the new function above that doc block.

…rame (#1018)

Quint's review: while folding, the held GOP was still buffered when the next
keyframe arrived, so the gate was never re-read and a session confirmed as
HDR only at readyToPlay kept folding until a seek. A keyframe now releases
the held GOP first and then reads the gate; a keyframe that starts the
bypass queues behind that GOP instead of overtaking it. A test drives the
gate both ways on a real FEL clip and checks the read order against the
demuxer. The two new functions no longer sit between an existing doc
comment and its function.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SeT6NgMt1vv32kPBhUmsUz

@quint-aether quint-aether Bot 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.

Automated review

Status: 🟢 Clean. Nothing left to fix, ready for a maintainer.

The PR adds LoadOptions.foldsDolbyVisionFEL and an automatic gate that pauses the FEL curve fold on a tvOS HDR10 panel without Dolby Vision, where the RPU does not reach the picture. The direction is right, and this push fixes everything from the last review.

Findings

  • Fixed: on a video keyframe, FelCurveLookahead now releases the held GOP first and then reads the gate. So a folding session moves into pass-through during playback, and the keyframe is queued behind the released GOP instead of overtaking it. togglesBothWaysInOrder covers both directions and checks the order against the raw demuxer. The "both directions" sentence in docs/dolby-vision-fel.md is now correct.
  • Fixed: hdrWriteExpectedToEngagePanel() and felGatePanelPresentsHDR now sit above the existing doc blocks, so currentPanelIsHDR() and sessionPanelPresentsHDR have their own comments back.

No new findings.

Checklist: CHANGELOG yes, docs yes, tests yes (gate truth tables, pass-through holds nothing back, toggling both ways in read order on the FEL clip when DV_FEL_TESTS_DIR is set), traits both ways yes

Needs a device run: on an SDR panel with rate-only matching, whether there is a short unfolded stretch before the refused HDR master clears the load-time prediction. Also the start and seek timings on a display where the prediction reads false but readyToPlay confirms HDR.

Thanks for the quick follow-up and the toggle test.

Automated review by Quint (Claude) of 5a1f7ac. It reads the code, it does not build or run it; a maintainer reviews and merges.

@superuser404notfound
superuser404notfound merged commit 6391b52 into main Nov 10, 2026
10 of 11 checks passed
@superuser404notfound
superuser404notfound deleted the feat/issue-1018-fel-fold-switch branch November 10, 2026 21:36
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