PrismCore
FFmpeg demuxt, Apple spielt ab.
Apples Wiedergabe-Stack kann Dinge, an die kein fremder Player herankommt — Hardware-Decoding, Dolby-Atmos-Passthrough, Dolby Vision, Match Content. Nur eine MKV öffnet er nicht. PrismCore remuxt jeden Container, den libavformat lesen kann, zu HLS-fMP4, liefert ihn von einem Loopback-Server und gibt einem einfachen AVPlayer eine Playlist-URL. Dieselbe Datei, Apples Engine.
Im Einsatz bei
Aether
Die Standard-Wiedergabe-Engine auf iPhone, iPad, Mac, Apple TV und Apple Vision Pro — bei jeder Installation aktiv, nicht hinter einem Schalter.
Es ist ein Swift-Package, kein Framework, das du bauen musst. Alles, was heute schon eine URL an AVPlayer gibt, kann es nutzen.
Was sich ändert, wenn du auf Play drückst
PrismCore soll unsichtbar sein: du öffnest einen Film, und er läuft. Was du dabei bekommst, ist genau das, was ein Player, der sein Bild selbst zeichnet, aufgeben muss.
Der Receiver bekommt den echten Ton
Dolby Atmos verlässt die Datei als Bitstream und kommt als Bitstream beim Receiver an — nirgends decodiert, nirgends eingeebnet. Der Receiver zeigt Atmos an, weil er wirklich Atmos bekommt und nicht dessen Stereo-Annäherung.
Der Fernseher schaltet wirklich auf Dolby Vision
Auf dem Apple TV wird das Panel programmiert, bevor die Wiedergabe beginnt — Bildrate, Dynamikumfang, Dolby Vision — mit demselben Handshake, den Apples eigene Apps bekommen. Einem Fernseher, der einen Dolby-Vision-Master ablehnt, wird der Film ohne diesen Anspruch erneut angeboten: du siehst ein Bild statt einer Fehlermeldung.
Es ist der Player, den du kennst
Spurmenü, Untertitel, Bild-in-Bild, AirPlay, Match Content, Spulen mit der Fernbedienung: alles davon ist Apples eigene Wiedergabe-Oberfläche — weil darunter tatsächlich Apples eigener Player läuft.
Kühles Gerät, ungerührter Akku
Das Bild decodiert der dedizierte Video-Chip, nicht die CPU, also kostet eine MKV genauso viel wie eine Datei, für die Apple Unterstützung mitbringt. Nichts wird transcodiert — nicht auf deinem Gerät und nicht auf dem Server, von dem die Datei kommt.
Springen bleibt sofortig
Eine Karte der ganzen Datei wird veröffentlicht, bevor das erste Bild ausgeliefert wird. Ein Sprung in die Mitte eines dreistündigen Films landet also dort und läuft, statt den Film von vorn neu vorzubereiten. Und beim Ziehen an der Suchleiste siehst du das Bild, auf das du zusteuerst — auch bei einer Datei, für die kein Server je Vorschauen erzeugt hat.
Nichts verlässt dein Gerät
Das Umpacken passiert auf dem Gerät und wird dem Player über 127.0.0.1 ausgeliefert — eine Loopback-Adresse, die das Netzwerk nie erreicht. Kein Schritt in der Cloud, kein Konto, und nichts über das, was du ansiehst, das irgendwohin gesendet werden könnte.
Der Trick, in einem Bild
MKV · MPEG-TS
Der Container, den Apple nicht öffnet
Demux
FFmpeg liest die Spuren
HLS-fMP4
Neu verpackt auf 127.0.0.1
AVPlayer
Apples eigener Player
Video · Audio · Untertitel
Die Datei wird gelesen, nicht umgewandelt
FFmpegs Demuxer öffnet den Container — MKV, MPEG-TS, AVI — und trennt dessen Inhalt in die einzelnen Spuren: Bild, jede Tonsprache, jeden Untertitel. Dabei wird nichts decodiert und nichts konvertiert; die Datei wird nur auseinandergelesen.
Die Spuren werden unverändert neu verpackt
Dasselbe komprimierte Bild und derselbe Ton wandern in fragmentierte MP4-Stücke, beschrieben von einer Playlist der Art, die AVPlayer nativ öffnet. Es ändert sich die Verpackung, nicht der Inhalt — Bit für Bit dasselbe Video und derselbe Ton wie in der Datei.
Eine lokale Adresse liefert es aus
Diese Stücke bekommt AVPlayer von 127.0.0.1, der Adresse, die das Gerät nie verlässt, als würde der Film gestreamt. Genau das ist der Trick: Apples Player streamt gern, was er als Datei zu öffnen verweigert.
Den Rest macht Apples Engine
Hardware-Decoding, Atmos-Passthrough, der Dolby-Vision-Handshake, das Spurmenü, PiP und AirPlay — nichts davon wird neu gebaut, denn aus Sicht von AVPlayer passiert hier nichts Ungewöhnliches.
Zwei Dinge lassen sich nicht umpacken und werden eigens behandelt. Untertitel, die Bilder von Text sind statt Text (die PGS in Blu-ray-Remuxen), liest Visions OCR direkt auf dem Gerät, und sie hängen sich als gewöhnliche Untertitel ein. Und eine Handvoll Codecs, die Apple gar nicht decodiert — VP9, MPEG-2, VC-1 — nimmt einen zweiten Weg, auf dem PrismCore das Bild selbst decodiert und zeichnet; dort fehlt die Oberfläche des Systemplayers, aber der Film läuft.
Was oft gefragt wird
Werden meine Dateien neu codiert?
Nein. Bild und Ton werden genau so kopiert, wie sie gelesen wurden — es ändert sich nur die Schachtel, in der sie liegen. Auch die Datei selbst wird nicht verändert: PrismCore liest sie ausschließlich.
Warum öffnet AVPlayer eine MKV dann nicht selbst?
Apple liefert Unterstützung für eine feste Liste von Containern, und MKV steht nicht darauf — selbst wenn Bild und Ton darin Formate sind, die Apple bestens decodiert. Es ist ein Verpackungsproblem, kein Decoding-Problem, und deshalb genügt Umpacken, um es zu lösen.
Was passiert mit TrueHD- oder DTS-Ton?
Apples Stack nimmt die nicht als Bitstream, sie können also nicht unangetastet durchlaufen. Statt sie auf Stereo zusammenzufalten, wandelt PrismCore sie in EAC3 um, mit jedem Kanal an seinem Platz — Surround bleibt Surround. Das Einzige, was diesen Weg nicht übersteht, ist Atmos innerhalb von TrueHD; Atmos in EAC3, was die meisten Remuxe tragen, läuft unverändert durch.
Muss mein Plex- oder Jellyfin-Server transcodieren?
Nein, und darin liegt ein guter Teil des Sinns. Der Server schickt die Originaldatei, das Umpacken passiert auf deinem Gerät — also kein serverseitiges Transcoding, das einen NAS zum Glühen bringt, und keine Qualität, die dabei verloren geht.
Kann ich es abschalten?
Ja — Einstellungen ▸ Wiedergabe in Aether. Es ist standardmäßig aktiv; schaltest du es aus, fällt die Wiedergabe genau wie früher auf die anderen Engines zurück, pro Installation und ohne Neuinstallation oder Zurücksetzen.
Startet die Wiedergabe langsamer?
Nein. Die Quelle wird einmal geöffnet und nur ihr Header gelesen: bei einer lokalen Datei sind das Dutzende Millisekunden, über ein Netzwerk etwa eine Zehntelsekunde — „Vorbereiten“ siehst du also ungefähr so lange wie bei einer Datei, die Apple direkt öffnet.
Alles weiter unten dreht sich darum, die Engine in die eigene App zu bringen. Wenn du als Zuschauer hier bist, hast du die ganze Geschichte schon — der Rest ist Installationsarbeit.
Was es abdeckt
Container und Codecs
Alles, was libavformat lesen kann — MKV, MPEG-TS, AVI. HEVC, H.264 und AV1 gehen per Stream-Copy direkt durch, zusammen mit AAC, AC3, EAC3, FLAC und ALAC. TrueHD, DTS, Opus und der Rest laufen über die Audiobrücke und kommen als EAC3 an, statt eingeebnet zu werden. Eine anamorphe Quelle behält die Form, die ihr Container angibt — in der pasp-Box, die AVPlayer respektiert.
Dolby Atmos, kein Downmix
EAC3+JOC wird unverändert kopiert und nie zu PCM decodiert — und die dec3-Box, die FFmpeg beim Stream-Copy verliert, wird wieder eingesetzt: das eine Signal, das AVFoundation den Dolby-Weg nehmen lässt statt schlicht DD+. Auf einem Receiver über HDMI bestätigt.
Dolby Vision und HDR
Profile 5 behält seinen dvh1-Eintrag, Profile 7 wird über libdovi zu einschichtigem 8.1, und auf tvOS wird das Panel programmiert, bevor AVPlayer die Playlist überhaupt sieht — der Handshake muss zuerst passieren, sonst wird die Variante direkt abgelehnt. Einen Master, den ein Fernseher ablehnt, versucht die Engine ohne diesen Anspruch erneut, statt zu scheitern.
Jede Spur und jeder Untertitel
Jede Tonspur wird zu einer Alternate Rendition mit Name, Sprache und Kanalzahl, sodass AVKits Spurmenü einfach funktioniert. Textuntertitel werden zu segmentiertem WebVTT, das PiP und AirPlay übersteht; PGS und VOBSUB tragen nur Bitmaps und werden darum auf dem Gerät mit Visions OCR gelesen und als gewöhnliche Renditions eingehängt — eine Spur tut nichts, bis ein Player sie wirklich abruft, weshalb ein Remux mit Dutzenden PGS-Spuren nichts kostet.
Springen wie in einer lokalen Datei
Ein an Keyframes ausgerichteter Segmentplan wird vor dem ersten Paket veröffentlicht, und ein Sprung außerhalb des erzeugten Fensters verankert den Demuxer bei Bedarf neu. Ein Cache mit Byte-Budget begrenzt die Platte, nicht die Sprungfähigkeit — verworfene Segmente werden einfach neu erzeugt, und ein Segment, das gerade ausgeliefert wird, ist nie das verworfene. Die Produktion hält sich etwa eine Minute vor dem letzten Segment, das der Player tatsächlich geholt hat, sodass eine mehrere Gigabyte große Datei nie gegen ihren eigenen Cache läuft — und der Abruf von der Quelle pendelt sich bei der echten Bitrate des Films ein statt bei der Leitungsgeschwindigkeit. Ein Container ohne eigenen Index bleibt dabei nicht stehen: die erste sequenzielle Wiedergabe sammelt jeden gelesenen Keyframe und schreibt die Karte weg, sodass die nächste Wiedergabe ab der ersten Sekunde darauf plant. Dieselbe Karte beantwortet SeekPreviewService, der den Keyframe zu jeder Position in ein Vorschaubild für die eigene Suchleiste des Hosts decodiert.
Ein Softwarepfad für den Rest
Codecs, die AVPlayer gar nicht decodiert — VP9, MPEG-2, VC-1 — laufen über libavcodec in einen AVSampleBufferDisplayLayer, zero-copy überall dort, wo VideoToolbox einen Hardware-Decoder hat. AV1 fragt das tatsächliche Silizium, nicht den Chipnamen, und verifiziert interlaced Quellen verlassen den nativen Pfad für den Deinterlacer — auf der GPU, auf den Frames, die der Decoder schon geliefert hat, sofern der FFmpeg-Build diesen Filter mitbringt.
Schneller Start
Eine Wiedergabe öffnete ihre Quelle früher zweimal — einmal für die Routing-Entscheidung des Hosts, einmal zum Produzieren — und über ein Netzwerk ist dieses zweite Öffnen eine echte Rundreise mitten in der Wartezeit, die der Nutzer ansieht. Die Sonde übergibt ihren offenen Kontext jetzt an die Session, jedes Öffnen liest nur, was ein sich selbst beschreibender Container braucht, und die internen Wartepunkte prüfen alle 10 ms statt alle 100. Ein 5,4-GB-Remux (HEVC/EAC3) über HTTP kommt von der Sonde zur Playlist in etwa 135 ms statt 520 — und eine Datei ohne Suchindex, die sonst eine Minute Scan bedeutet, startet trotzdem, mit einem begrenzten Plan.
Eine Lizenz, die im App Store funktioniert
LGPL-2.1-or-later mit einer Application Store Exception. Eine signierte App kann niemandem erlauben, sie neu zu linken — damit standen reine LGPL und Store-Vertrieb im Widerspruch; die Ausnahme hebt genau diese Anforderung für Store-Builds auf, während Änderungen an PrismCore selbst LGPL bleiben und veröffentlicht werden müssen. Die öffentliche API ist seit 1.0 stabil — ein Bruch bedeutet eine Major-Version, und jedes Release steht im Changelog.
Im Vergleich
Auf Apple-Plattformen wählt man sonst zwischen einem Player, der das Gute behält, aber nur Apples Container öffnet, und einem, der alles öffnet, aber eigene Frames rendert und Audio zu PCM decodiert — genau dort sterben Atmos und Dolby Vision. PrismCore ist gar kein Player: es füttert AVPlayer, also gibt es nichts aufzugeben.
| PrismCore | AVPlayer | VLCKit | libmpv | |
|---|---|---|---|---|
| Spielt MKV, MPEG-TS, AVI | ||||
| Dolby Atmos als Bitstream durchgereicht | ||||
| Dolby Vision auf dem Display aktiv | ||||
| Match Content auf tvOS — Bildrate und Bereich | ||||
| Apples eigene Player-UI: Spurmenü, PiP, AirPlay | ||||
| VP9, MPEG-2 und VC-1 |
VLCKit und libmpv zeichnen in ihre eigene Ebene und geben dir PCM — deshalb scheitern bei ihnen die mittleren Zeilen. Das ist die Folge davon, den Renderpfad zu besitzen, kein Versehen. AVPlayer scheitert an der ersten und letzten Zeile, weil er nur Container annimmt, für die Apple Unterstützung liefert.
Loslegen
Package hinzufügen, dann eine URL übergeben. Ein Einstiegspunkt prüft die Quelle und gibt entweder eine Playlist für AVPlayer oder eine bereits gestartete Software-Pipeline zurück.
.package(url: "https://github.com/Wenzlik/PrismCore.git", from: "1.8.7")switch try await PrismCoreEngine.open(url: mkvURL) {
case .remux(let session, let playlist):
player.replaceCurrentItem(with: AVPlayerItem(url: playlist))
…
await session.stop()
case .software(let pipeline):
hostView.layer.addSublayer(pipeline.displayLayer!)
pipeline.play()
}Sobald die erste Wiedergabe läuft, lohnen sich zwei Optionen. Gib der Session ein Cache-Verzeichnis, und ein Container ohne eigenen Index sammelt sich beim Abspielen einen — die nächste Wiedergabe sucht dann wie eine indexierte Datei. Dasselbe Verzeichnis trägt die Vorschaubilder für die Suchleiste: eine eigene kleine Pipeline — separater Kontext, Decoding auf der CPU, Cache pro Keyframe — die deshalb nie die Wiedergabe aufhält, zu der sie gehört, welche Engine auch läuft.
let session = try PrismCoreSession(url: mkvURL, keyframeIndexCacheDirectory: caches)
let previews = SeekPreviewService(url: mkvURL, keyframeIndexCacheDirectory: caches)
let frame: CGImage = try await previews.thumbnail(at: 42 * 60)Mindestversionen sind iOS 16, tvOS 17, macOS 14 und visionOS 1. FFmpeg kommt über MPVKits dynamische xcframeworks, ein Host mit MPVKit fügt also keine neuen Binärabhängigkeiten hinzu. Wenn deine CI die Abhängigkeiten auflöst, pinne eine exakte Version und halte die eingecheckte Package.resolved damit im Gleichschritt — sonst laufen ein Gerätebuild und ein TestFlight-Build still auf verschiedenen Engines.
Willst du einfach nur etwas schauen?
Das war die Entwicklerhälfte der Seite. Wenn du hier bist, um deine eigenen Filme und Serien zu schauen: PrismCore macht seine Arbeit längst in Aether — du musst nie an es denken.
Aether ansehenPrismCore wird von Václav Zmrhal gebaut · zmrhal.cz