refactor(player): centralize playback opening

close #1280
This commit is contained in:
edde746
2026-06-10 02:26:26 +02:00
parent 18642cae15
commit cd9498abb8
51 changed files with 3016 additions and 1422 deletions
+45 -4
View File
@@ -72,6 +72,12 @@ struct ServerDisplayCriteria {
let gamma: String?
let primaries: String?
let colorMatrix: String?
/// Whether the server metadata carried actual color/DoVi information
/// only then may the prime lock out mpv-derived color updates.
var hasColorInfo: Bool {
doviProfile > 0 || gamma != nil || primaries != nil || colorMatrix != nil
}
}
class MpvPlayerCoreBase: NSObject {
@@ -97,6 +103,7 @@ class MpvPlayerCoreBase: NSObject {
private var cachedVideoPrimaries: String?
private var cachedVideoColorMatrix: String?
private var serverDisplayCriteriaActive = false
private var serverCriteriaLocksColor = false
private var lastServerCriteria: ServerDisplayCriteria?
private var cachedDvConversionMode = "auto"
private var cachedDvConversionLogEnabled = false
@@ -196,11 +203,41 @@ class MpvPlayerCoreBase: NSObject {
colorMatrix: String?
) -> Bool { false }
/// Whether the mpv-derived caches indicate an HDR/DV source mirrors the
/// Dart-side MediaDisplayCriteria.isHdr tag check. Call under cacheLock.
private static func looksHdr(
doviProfile: Int64, sigPeak: Double, gamma: String?, primaries: String?, colorMatrix: String?
) -> Bool {
if doviProfile > 0 || sigPeak > 1 { return true }
let tags = [gamma, primaries, colorMatrix]
.compactMap { $0?.lowercased() }
.joined(separator: " ")
.replacingOccurrences(of: "[^a-z0-9]", with: "", options: .regularExpression)
return ["hlg", "arib", "pq", "smpte2084", "st2084", "bt2020"].contains { tags.contains($0) }
}
func scheduleDisplayCriteriaUpdate() {
cacheLock.lock()
if serverDisplayCriteriaActive {
cacheLock.unlock()
return
// A color-bearing server prime owns the display mode for the item. An
// fps-only prime is just an early hint: demote it once the decoded
// stream proves HDR/DV so the real color tags reach the display,
// otherwise keep suppressing redundant SDR re-applies.
if serverCriteriaLocksColor
|| !Self.looksHdr(
doviProfile: cachedDoviProfile,
sigPeak: cachedLastSigPeak,
gamma: cachedVideoGamma,
primaries: cachedVideoPrimaries,
colorMatrix: cachedVideoColorMatrix
)
{
cacheLock.unlock()
return
}
serverDisplayCriteriaActive = false
serverCriteriaLocksColor = false
lastServerCriteria = nil
}
let profile = cachedDoviProfile
let level = cachedDoviLevel
@@ -229,16 +266,17 @@ class MpvPlayerCoreBase: NSObject {
}
}
func setServerDisplayCriteria(_ criteria: ServerDisplayCriteria?) {
func setServerDisplayCriteria(_ criteria: ServerDisplayCriteria?, completion: ((Bool) -> Void)? = nil) {
cacheLock.lock()
serverDisplayCriteriaActive = criteria != nil
serverCriteriaLocksColor = criteria?.hasColorInfo ?? false
lastServerCriteria = criteria
cacheLock.unlock()
let apply = { [weak self] in
guard let self else { return }
guard let criteria else {
_ = self.updateDisplayCriteria(
let applied = self.updateDisplayCriteria(
doviProfile: 0,
doviLevel: 0,
doviCompatibilityId: nil,
@@ -250,6 +288,7 @@ class MpvPlayerCoreBase: NSObject {
primaries: nil,
colorMatrix: nil
)
completion?(applied)
return
}
@@ -268,9 +307,11 @@ class MpvPlayerCoreBase: NSObject {
if !applied {
self.cacheLock.lock()
self.serverDisplayCriteriaActive = false
self.serverCriteriaLocksColor = false
self.cacheLock.unlock()
self.scheduleDisplayCriteriaUpdate()
}
completion?(applied)
}
if Thread.isMainThread {
@@ -14,10 +14,40 @@ protocol MpvPluginShared: AnyObject, MpvPlayerDelegate {
func setPlayerVisible(_ visible: Bool, restoreOnWindowVisible: Bool)
func updatePlayerFrame()
/// Invoked after the `pause` property is applied via setProperty so each
/// platform can sync its PiP/idle bookkeeping (iOS: invalidate the PiP
/// playback state + timebase; macOS: setPlaying/setPaused).
func didSetPauseProperty(value: String)
}
extension MpvPluginShared {
func handleSetProperty(call: FlutterMethodCall, result: @escaping FlutterResult) {
guard let args = call.arguments as? [String: Any],
let name = args["name"] as? String,
let value = args["value"] as? String
else {
result(
FlutterError(
code: "INVALID_ARGS", message: "Missing 'name' or 'value' argument",
details: nil))
return
}
guard let core = coreBase else {
result(nil)
return
}
core.setPropertyAsync(name, value: value) { [weak self] _ in
if name == "pause" {
self?.didSetPauseProperty(value: value)
}
result(nil)
}
}
func handleGetProperty(call: FlutterMethodCall, result: @escaping FlutterResult) {
guard let args = call.arguments as? [String: Any],
let name = args["name"] as? String