Skip to content

DolbyVisionFelCurves: skip the curve fold when the display does not take Dolby Vision (and a per-load switch) #1018

Open

Description

@samimt55

Hi, thanks for the curve fold in 7.61.0 and for the clear write-up of when to pick it over the dual-layer route. We ship it on 7.62.1, on by default as the docs recommend.

What we found. On a display without Dolby Vision the fold still runs. The engine sees the display correctly and plays HDR10, but the Profile 7 source is still converted to Profile 8.1, so felLookaheadForRead() arms the fold (it checks only convertP7Active, !isLive and the absence of an enhancement-route tap):

[DisplayCapabilities] observed: hdr=true hdr10=true hlg=true dv=false
[AetherEngine] load ... source-format=dolbyVision effective-format=hdr10 rate=23.976
[FelCurves] FEL source: mapping kept in the Profile 8.1 RPU, enhancement-layer luma residual folded into its luma curve per scene
[HLSVideoEngine] prepared: codec=hvc1.2.4.H153.90,ec-3 supplemental=dvh1.08.06/db1p ... DV=profile7
[HLSVideoEngine] serving on ... (dvModeAvailable=false effectiveDvMode=false panelIsHDR=true ...)

The panel shows the HDR10 base layer, so the folded RPU never reaches a Dolby Vision decoder. We compared two builds of the same code, one with the trait and one without, on the same scene of a UHD Blu-ray FEL title (Apple TV 4K, 3rd generation, tvOS 27, an HDR10/HDR10+ TV, source over HTTPS from a remote server):

Start Fold built in Fold not built
From the beginning 3.09 s to first frame (not measured; 4.3 s on 7.59.0 before the upgrade)
Resume at 65:00, run 1 7.01 s 3.10 s
Resume at 65:00, run 2 3.61 s 2.97 s

So a resume costs 0.5 to 4 s more with the fold. Watching both builds side by side twice, we saw no visible difference on this display, which is what we would expect if the RPU is not applied.

Suggestions.

  1. Arm the fold only when the display takes Dolby Vision (the same signal behind dvModeAvailable), and skip the GOP hold-back and the two-layer decodes otherwise. A log line at load stating whether the fold is armed, and why not, would help reports.
  2. A per-load switch in LoadOptions (for example foldDolbyVisionFEL: Bool, defaulting to true when the trait is built in, so today's behaviour is unchanged), read once per load by felLookaheadForRead() and carried into reloadAtCurrentPosition(). That would let a host turn the fold off for a title a viewer reports, and run A/B checks on one build. Without the trait the field would be ignored, like preferDualLayerDolbyVision without DualLayerDolbyVision.

Happy to test a branch on an Apple TV 4K (3rd generation) with this display.

Activity

  1. quint-aether commented on Nov 10, 2026

    @quint-aether

    This is related to #988, the request for an RPU-only FEL correction that the DolbyVisionFelCurves fold answers. On main, felLookaheadForRead() in Sources/AetherEngine/Video/HLSSegmentProducer.swift arms the fold based only on convertP7Active, !isLive and the absence of an enhancement-route tap, which matches what you describe. Whether to gate the fold on the display and add a per-load switch is a decision for the maintainer.

    Automated triage by Quint (Claude). A maintainer reads every issue and will follow up.

  2. superuser404notfound commented on Nov 10, 2026

    @superuser404notfound
    Owner

    Thanks for the measurements and the clear write-up. You were right about the waste, and I measured where it actually happens before gating it, because dvModeAvailable turned out to be the wrong signal.

    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:

    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 yes

    A Mac and a Dolby Vision display apply it too. So the fold is wasted in exactly your case: tvOS, no Dolby Vision, panel in HDR10, without forceDolbyVisionOnNonDVDisplay.

    Merged into main in #1019, in the next release:

    1. The fold pauses on its own in that case. The engine predicts it at load (range matching on, an HDR-capable display, HDR criteria written by the engine), confirms it when the HDR master reaches readyToPlay, and clears it if the display refuses the master. The lookahead re-reads this at every keyframe and passes packets through without holding a GOP back or decoding anything. Logged as [FelCurves] fold paused. From a P7 FEL source over the network on the same box, the first load went from 5.04 to 5.14 s down to 4.33 to 4.42 s, the same as with the fold off, and seeks match too.
    2. LoadOptions.foldsDolbyVisionFEL (default true), the per-load switch you suggested, carried by reloadAtCurrentPosition(applying:) and ignored without the trait. The load logs [FelCurves] fold not armed: <reason>.

    One more thing worth considering for your app: with forceDolbyVisionOnNonDVDisplay on, tvOS applies the RPU on an HDR10 panel, so the fold reaches the picture there instead of being skipped. The unedited frames came out identical to the plain route in my test (no colour shift). The engine default stays off; Sodalite now turns it on by default on tvOS.

    If you can rerun your resume test once the release is out, I'd be glad to hear the numbers.

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

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions