Matroska geht jetzt an AVPlayer, nicht mehr an VLC
Ein Blu-ray-Rip liegt als Matroska vor, und AVFoundation oeffnet Matroska nicht — obwohl das Bild darin H.264 oder HEVC ist und der Ton AC3, also alles, was AVPlayer bestens kann. Im Weg stand allein die Verpackung. Dafuer gibt es jetzt einen dritten Weg neben Durchreichen und Neurechnen: umpacken. Dieselben Stroeme, Byte fuer Byte, in eine MP4. Kein Bild wird angefasst, es geht nichts an Qualitaet verloren, und den Server kostet es fast nichts. Entscheidend ist dabei `Protocol: http` statt `hls`. Eine Abspielliste laesst sich nicht vorausladen — AVPlayer holt Segment fuer Segment, und Apple laesst uns dazwischen nicht eingreifen. Eine fortlaufende Datei kommt ueber gewoehnliche Bereichsanfragen, und die kann man so weit vorausholen, wie man will. Der Vorratswunsch steht dort deshalb bei zehn Minuten statt bei einer. Der Gewinn ist gross: solche Titel bekommen Bild-in-Bild, AirPlay und die Systembedienung, die es bei VLC nicht gibt. Umgepackt wird nur, wenn **allein** die Schachtel im Weg steht. Stimmt auch nur ein Codec nicht — DTS, TrueHD, AV1 —, fehlt nicht der Zugang zur Datei, sondern das Koennen; dann bleibt es bei VLC. Sechs Tests halten die Grenze fest, in beide Richtungen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
806eb381c7
commit
62691fc2bc
@@ -41,7 +41,8 @@ extension JellyfinBackend {
|
||||
sourceID: sourceID,
|
||||
transcode: transcode,
|
||||
audioStreamIndex: intent.audioStreamIndex,
|
||||
subtitleStreamIndex: intent.subtitleStreamIndex
|
||||
subtitleStreamIndex: intent.subtitleStreamIndex,
|
||||
remux: transcode.prefersRemux
|
||||
)
|
||||
|
||||
let source = info.mediaSources?.first { $0.id == sourceID } ?? info.mediaSources?.first
|
||||
@@ -59,7 +60,12 @@ extension JellyfinBackend {
|
||||
}
|
||||
|
||||
var adresse = Self.limiting(height: transcode.resolution, in: url)
|
||||
if transcode.prefersAdaptive { adresse = Self.adaptive(adresse) }
|
||||
// Beim Umpacken **keine** Leiter: es gibt nur eine Fassung, nämlich
|
||||
// die Datei selbst. Und `master.m3u8` wäre ohnehin das Gegenteil
|
||||
// dessen, worum es geht — eine Abspielliste statt einer Datei.
|
||||
if transcode.prefersAdaptive, !transcode.prefersRemux {
|
||||
adresse = Self.adaptive(adresse)
|
||||
}
|
||||
|
||||
return PlaybackTarget(
|
||||
url: adresse,
|
||||
@@ -123,18 +129,40 @@ extension JellyfinBackend {
|
||||
sourceID: String,
|
||||
transcode: TranscodeSettings,
|
||||
audioStreamIndex: Int? = nil,
|
||||
subtitleStreamIndex: Int? = nil
|
||||
subtitleStreamIndex: Int? = nil,
|
||||
remux: Bool = false
|
||||
) async throws(MediaBackendError) -> JellyfinPlaybackInfo {
|
||||
// Jellyfin rechnet in Bit, die App in Kilobit.
|
||||
let bitsPerSecond = (transcode.maximumBitrate ?? 8_000) * 1_000
|
||||
|
||||
// **Umpacken: eine fortlaufende MP4, und die Ströme unverändert.**
|
||||
//
|
||||
// `Protocol: http` statt `hls` ist der entscheidende Unterschied. Eine
|
||||
// Abspielliste lässt sich nicht vorausladen — AVPlayer holt Segment
|
||||
// für Segment und Apple lässt uns dazwischen nicht eingreifen. Eine
|
||||
// fortlaufende Datei kommt dagegen über gewöhnliche Bereichsanfragen,
|
||||
// und die kann man so weit vorausholen, wie man will.
|
||||
//
|
||||
// Die Codecs stehen genau so breit wie das, was AVPlayer wirklich
|
||||
// kann: trifft der Server eine Übereinstimmung, kopiert er den Strom,
|
||||
// statt ihn neu zu rechnen. Genau dafür ist der Weg da.
|
||||
let umpacken: [String: Any] = [
|
||||
"Type": "Video",
|
||||
"Container": "mp4",
|
||||
"Protocol": "http",
|
||||
"VideoCodec": "h264,hevc",
|
||||
"AudioCodec": "aac,ac3,eac3,mp3",
|
||||
"Context": "Streaming",
|
||||
"MaxAudioChannels": "8",
|
||||
]
|
||||
|
||||
let profile: [String: Any] = [
|
||||
"MaxStreamingBitrate": bitsPerSecond,
|
||||
// Leer heißt: nichts geht unverändert. An dieser Stelle ist bereits
|
||||
// entschieden, dass umgerechnet werden soll — dem Server die Wahl
|
||||
// zu lassen hieße, die Entscheidung zweimal zu treffen.
|
||||
"DirectPlayProfiles": [],
|
||||
"TranscodingProfiles": [[
|
||||
"TranscodingProfiles": remux ? [umpacken] : [[
|
||||
"Type": "Video",
|
||||
"Container": "ts",
|
||||
"Protocol": "hls",
|
||||
|
||||
Reference in New Issue
Block a user