diff --git a/ios/Runner/MpvPlayer/MpvPlayerCore.swift b/ios/Runner/MpvPlayer/MpvPlayerCore.swift index 06272af2..8a3cf14f 100644 --- a/ios/Runner/MpvPlayer/MpvPlayerCore.swift +++ b/ios/Runner/MpvPlayer/MpvPlayerCore.swift @@ -268,10 +268,19 @@ class MpvPlayerCore: MpvPlayerCoreBase { doviCompatibilityId: doviCompatibilityId ) let sourceRange: DisplayDynamicRange = sourceHasDolbyVision ? .dolbyVision : sourceBaseRange - var displayRange: DisplayDynamicRange = - sourceHasDolbyVision - ? .dolbyVision - : Self.supportedDisplayDynamicRange(for: sourceBaseRange) + // The HDR toggle (`hdrEnabled`) is authoritative on tvOS: when it's off, + // drive the HDMI link in SDR regardless of the source — Dolby Vision + // included — so turning HDR off actually leaves DV mode (issue #1262). + // This is the only path that gates the HDMI mode on tvOS; + // target-colorspace-hint is inert in the avfoundation VO and EDR is iOS. + var displayRange: DisplayDynamicRange + if !hdrEnabled { + displayRange = .sdr + } else if sourceHasDolbyVision { + displayRange = .dolbyVision + } else { + displayRange = Self.supportedDisplayDynamicRange(for: sourceBaseRange) + } guard displayManager.isDisplayCriteriaMatchingEnabled else { clearDisplayCriteria(displayManager, reason: "matching disabled") return false @@ -288,7 +297,7 @@ class MpvPlayerCore: MpvPlayerCoreBase { doviProfile: doviProfile, doviLevel: doviLevel, doviCompatibilityId: doviCompatibilityId) - if formatDescription == nil, sourceHasDolbyVision { + if formatDescription == nil, sourceHasDolbyVision, hdrEnabled { displayRange = sourceBaseRange formatDescription = Self.makeDisplayFormatDescription( dynamicRange: displayRange, diff --git a/shared/apple/MpvPlayer/MpvPlayerCoreBase.swift b/shared/apple/MpvPlayer/MpvPlayerCoreBase.swift index 36bcdbfd..f7d2e541 100644 --- a/shared/apple/MpvPlayer/MpvPlayerCoreBase.swift +++ b/shared/apple/MpvPlayer/MpvPlayerCoreBase.swift @@ -97,6 +97,7 @@ class MpvPlayerCoreBase: NSObject { private var cachedVideoPrimaries: String? private var cachedVideoColorMatrix: String? private var serverDisplayCriteriaActive = false + private var lastServerCriteria: ServerDisplayCriteria? private var cachedDvConversionMode = "auto" private var cachedDvConversionLogEnabled = false var hdrEnabled: Bool { @@ -231,6 +232,7 @@ class MpvPlayerCoreBase: NSObject { func setServerDisplayCriteria(_ criteria: ServerDisplayCriteria?) { cacheLock.lock() serverDisplayCriteriaActive = criteria != nil + lastServerCriteria = criteria cacheLock.unlock() let apply = { [weak self] in @@ -278,6 +280,21 @@ class MpvPlayerCoreBase: NSObject { } } + /// Re-evaluate the tvOS HDMI display mode using the most recent criteria. + /// On tvOS the HDR toggle only reaches the display through this path, so the + /// runtime toggle calls this to switch DV/HDR ⇄ SDR without reloading. + func reapplyDisplayCriteria() { + cacheLock.lock() + let criteria = lastServerCriteria + cacheLock.unlock() + + if let criteria { + setServerDisplayCriteria(criteria) + } else { + scheduleDisplayCriteriaUpdate() + } + } + func setupMpv() -> Bool { #if os(macOS) guard let renderLayer = metalLayer else { return false } @@ -509,6 +526,15 @@ class MpvPlayerCoreBase: NSObject { DispatchQueue.main.async { self.updateEDRMode(sigPeak: sigPeak) } + + // On tvOS the toggle only takes effect through the HDMI display-mode path + // (target-colorspace-hint is inert in the avfoundation VO and EDR is + // iOS-only), so re-evaluate the display criteria with the new flag. + #if os(tvOS) + DispatchQueue.main.async { + self.reapplyDisplayCriteria() + } + #endif } /// PiP presents the AVSampleBufferDisplayLayer directly, so subtitles must