import Foundation /// Wie ein Titel abgespielt werden soll. public struct PlaybackDecision: Sendable, Equatable { public enum Method: Sendable, Equatable { /// Die Datei wird unverändert übertragen und lokal dekodiert. case directPlay /// Der Server reicht das Bild durch und legt es in eine andere /// Schachtel — den Ton rechnet er um, falls nötig. /// /// **Der dritte Weg, und der wichtigste für diesen Bestand.** Ein /// Blu-ray-Rip liegt als Matroska vor, und AVFoundation öffnet /// Matroska nicht — obwohl das Bild darin H.264 oder HEVC ist und der /// Ton AAC oder AC3, also alles, was AVPlayer bestens kann. Im Weg /// steht allein die Verpackung. /// /// **Das Bild wird dabei nie angefasst.** Es geht Byte für Byte in /// eine MP4, und das kostet den Server fast nichts — anders als beim /// Neurechnen. /// /// **Der Ton kann es müssen.** Steht DTS, TrueHD oder Vorbis darin, /// kennt AVPlayer die Spur nicht; der Server kodiert dann genau diese /// eine Spur nach AC3 oder AAC. Das kostet Tonqualität — und sonst /// nichts, vor allem keine einzige Bildzeile. Ob es im Einzelfall /// passiert ist, steht in `rationale`: `audioCodecUnsupported`. /// /// Der Gewinn ist gross: solche Titel laufen damit im Systemplayer, /// mit Bild-in-Bild, AirPlay und Systembedienung — und es muss nicht /// das ganze Bild neu gerechnet werden. case remux /// Der Server rechnet um. Ab Phase 2; `maximumBitrate` in Kilobit. case transcode(maximumBitrate: Int?) } /// Warum es so entschieden wurde. /// /// Wandert in die technischen Infos auf der Detailseite und ins Protokoll. /// Ohne diese Begründung ist „warum ruckelt das" nicht zu beantworten. public enum Rationale: Sendable, Equatable { case nativelySupported case containerUnsupported(String) case videoCodecUnsupported(String) case audioCodecUnsupported(String) /// Der Server hat die Datei noch nicht analysiert. case streamsUnknown case bitrateExceedsLimit(mediaBitrate: Int, limit: Int) /// Transcoding wäre passender, ist aber (noch) nicht verfügbar. case transcodingUnavailable /// Im Player ausdrücklich eine Stufe gewählt. case qualityChosen } public let method: Method public let rationale: [Rationale] public init(method: Method, rationale: [Rationale]) { self.method = method self.rationale = rationale } public var isDirectPlay: Bool { if case .directPlay = method { return true } return false } }