refactor(tv): unify subtitle track selector and search into tabbed sheet

This commit is contained in:
Fredrik Burmester
2026-01-18 11:13:57 +01:00
parent ee3a288fa0
commit c515d037cf
12 changed files with 826 additions and 399 deletions

View File

@@ -4,12 +4,21 @@ import CoreMedia
import CoreVideo
import AVFoundation
/// HDR mode detected from video properties
enum HDRMode {
case sdr
case hdr10
case dolbyVision
case hlg
}
protocol MPVLayerRendererDelegate: AnyObject {
func renderer(_ renderer: MPVLayerRenderer, didUpdatePosition position: Double, duration: Double)
func renderer(_ renderer: MPVLayerRenderer, didChangePause isPaused: Bool)
func renderer(_ renderer: MPVLayerRenderer, didChangeLoading isLoading: Bool)
func renderer(_ renderer: MPVLayerRenderer, didBecomeReadyToSeek: Bool)
func renderer(_ renderer: MPVLayerRenderer, didBecomeTracksReady: Bool)
func renderer(_ renderer: MPVLayerRenderer, didDetectHDRMode mode: HDRMode, fps: Double)
}
/// MPV player using vo_avfoundation for video output.
@@ -427,7 +436,10 @@ final class MPVLayerRenderer {
self.delegate?.renderer(self, didChangeLoading: false)
}
}
// Detect HDR mode for tvOS display switching
detectHDRMode()
case MPV_EVENT_SEEK:
// Seek started - show loading indicator and enable immediate progress updates
isSeeking = true
@@ -793,6 +805,53 @@ final class MPVLayerRenderer {
return Int(aid)
}
// MARK: - HDR Detection
/// Detects the HDR mode of the currently playing video by reading mpv properties
private func detectHDRMode() {
guard let handle = mpv else { return }
// Get video color properties
let primaries = getStringProperty(handle: handle, name: "video-params/primaries")
let gamma = getStringProperty(handle: handle, name: "video-params/gamma")
// Get FPS for display criteria
var fps: Double = 24.0
getProperty(handle: handle, name: "container-fps", format: MPV_FORMAT_DOUBLE, value: &fps)
if fps <= 0 { fps = 24.0 }
Logger.shared.log("HDR Detection - primaries: \(primaries ?? "nil"), gamma: \(gamma ?? "nil"), fps: \(fps)", type: "Info")
// Determine HDR mode based on color properties
// bt.2020 primaries with PQ gamma = HDR10 or Dolby Vision
// bt.2020 primaries with HLG gamma = HLG
// Otherwise SDR
let hdrMode: HDRMode
if primaries == "bt.2020" || primaries == "bt.2020-ncl" {
if gamma == "pq" {
// PQ gamma indicates HDR10 or Dolby Vision
// We'll use hdr10 as the base, Dolby Vision detection would need codec inspection
// For DV Profile 8.1, HDR10 fallback should work
hdrMode = .hdr10
} else if gamma == "hlg" {
hdrMode = .hlg
} else {
// bt.2020 without HDR gamma - still request HDR mode for wide color
hdrMode = .hdr10
}
} else {
hdrMode = .sdr
}
Logger.shared.log("HDR Detection - detected mode: \(hdrMode)", type: "Info")
DispatchQueue.main.async { [weak self] in
guard let self else { return }
self.delegate?.renderer(self, didDetectHDRMode: hdrMode, fps: fps)
}
}
// MARK: - Technical Info
func getTechnicalInfo() -> [String: Any] {

View File

@@ -308,6 +308,9 @@ class MpvPlayerView: ExpoView {
}
deinit {
#if os(tvOS)
resetDisplayCriteria()
#endif
pipController?.stopPictureInPicture()
renderer?.stop()
displayLayer.removeFromSuperlayer()
@@ -376,8 +379,63 @@ extension MpvPlayerView: MPVLayerRendererDelegate {
self.onTracksReady([:])
}
}
func renderer(_: MPVLayerRenderer, didDetectHDRMode mode: HDRMode, fps: Double) {
#if os(tvOS)
setDisplayCriteria(for: mode, fps: Float(fps))
#endif
}
}
// MARK: - tvOS HDR Display Criteria
#if os(tvOS)
import AVKit
extension MpvPlayerView {
/// Sets the preferred display criteria for HDR content on tvOS
func setDisplayCriteria(for hdrMode: HDRMode, fps: Float) {
guard let window = self.window else {
print("🎬 HDR: No window available for display criteria")
return
}
let manager = window.avDisplayManager
switch hdrMode {
case .sdr:
print("🎬 HDR: Setting display criteria to SDR (nil)")
manager.preferredDisplayCriteria = nil
case .hdr10:
print("🎬 HDR: Setting display criteria to HDR10, fps: \(fps)")
manager.preferredDisplayCriteria = AVDisplayCriteria(
refreshRate: fps,
videoDynamicRange: "hdr10"
)
case .dolbyVision:
print("🎬 HDR: Setting display criteria to Dolby Vision, fps: \(fps)")
manager.preferredDisplayCriteria = AVDisplayCriteria(
refreshRate: fps,
videoDynamicRange: "dolbyVision"
)
case .hlg:
print("🎬 HDR: Setting display criteria to HLG, fps: \(fps)")
manager.preferredDisplayCriteria = AVDisplayCriteria(
refreshRate: fps,
videoDynamicRange: "hlg"
)
}
}
/// Resets display criteria when playback ends
func resetDisplayCriteria() {
guard let window = self.window else { return }
print("🎬 HDR: Resetting display criteria")
window.avDisplayManager.preferredDisplayCriteria = nil
}
}
#endif
// MARK: - PiPControllerDelegate
extension MpvPlayerView: PiPControllerDelegate {