Aether
Código abierto · paquete Swift

PrismCore

FFmpeg demultiplexa, Apple reproduce.

La pila de reproducción de Apple hace cosas que ningún reproductor de terceros alcanza — descodificación por hardware, Dolby Atmos en passthrough, Dolby Vision, Match Content. Solo que no abre un MKV. PrismCore reempaqueta cualquier contenedor que libavformat sepa leer en HLS-fMP4, lo sirve desde un servidor de bucle local y le da a un AVPlayer normal una URL de lista de reproducción. El mismo archivo, el motor de Apple.

Ver en GitHub1.8.7LGPL-2.1+ · excepción para la App Store

Funcionando en

Aether

El motor de reproducción por defecto en iPhone, iPad, Mac, Apple TV y Apple Vision Pro — activo en cada instalación, no detrás de un interruptor.

Descargar Aether

Es un paquete Swift, no un framework que haya que compilar. Puede usarlo cualquier cosa que ya le pase una URL a AVPlayer.

Qué cambia cuando le das a reproducir

PrismCore está hecho para ser invisible: abres una película y se reproduce. Lo que te da es justo todo aquello a lo que un reproductor que dibuja su propia imagen tiene que renunciar.

Tu receptor recibe la banda sonora de verdad

El Dolby Atmos sale del archivo como bitstream y llega al receptor como bitstream: no se descodifica ni se aplana por el camino. El receptor enciende el rótulo de Atmos porque le están dando Atmos, no una aproximación en estéreo.

El televisor sí entra en Dolby Vision

En el Apple TV el panel se programa antes de que empiece la reproducción — frecuencia de imagen, rango dinámico, Dolby Vision — con el mismo intercambio que reciben las apps de Apple. A un televisor que rechaza un máster de Dolby Vision se le ofrece la película otra vez sin esa declaración: ves imagen en lugar de un error.

Es el reproductor que ya conoces

El menú de pistas, los subtítulos, Imagen en imagen, AirPlay, Match Content, avanzar con el mando: todo eso es la interfaz de reproducción de Apple, porque debajo está de verdad el reproductor de Apple.

Dispositivo fresco, batería tranquila

La imagen la descodifica el chip de vídeo dedicado y no la CPU, así que un MKV cuesta lo mismo que un archivo con soporte nativo. Nada se transcodifica: ni en tu dispositivo ni en el servidor del que viene el archivo.

Moverse por la película sigue siendo instantáneo

Un mapa del archivo completo se publica antes de servir el primer fotograma, así que un salto a la mitad de una película de tres horas aterriza ahí y reproduce, en vez de preparar la película otra vez desde el principio. Y al arrastrar la barra de avance ves el fotograma al que te diriges, incluso en un archivo para el que ningún servidor generó nunca miniaturas.

Nada sale de tu dispositivo

El reempaquetado ocurre en el dispositivo y se le sirve al reproductor por 127.0.0.1, una dirección de bucle local que nunca llega a la red. Ningún paso en la nube, ninguna cuenta y nada sobre lo que ves que se pueda enviar a ningún sitio.

El truco, en una imagen

  1. MKV · MPEG-TS

    El contenedor que Apple no abre

  2. Demux

    FFmpeg lee las pistas

  3. HLS-fMP4

    Reempaquetado en 127.0.0.1

  4. AVPlayer

    El reproductor propio de Apple

  5. Vídeo · Audio · Subtítulos

  1. El archivo se lee, no se convierte

    El demultiplexor de FFmpeg abre el contenedor — MKV, MPEG-TS, AVI — y separa lo que hay dentro en sus pistas: la imagen, cada idioma de audio, cada subtítulo. Nada se descodifica ni se convierte; el archivo solo se lee por partes.

  2. Las pistas se reempaquetan intactas

    Esa misma imagen y ese mismo sonido comprimidos se colocan en fragmentos MP4, descritos por una lista del tipo que AVPlayer abre de forma nativa. Cambia el envoltorio, no el contenido: bit a bit el mismo vídeo y el mismo audio que había en el archivo.

  3. Los sirve una dirección local

    Esos fragmentos llegan a AVPlayer desde 127.0.0.1, la dirección que nunca sale del dispositivo, como si la película se estuviera transmitiendo. Ahí está todo el truco: el reproductor de Apple transmite encantado lo que se niega a abrir como archivo.

  4. El motor de Apple hace el resto

    Descodificación por hardware, Atmos en passthrough, el intercambio de Dolby Vision, el menú de pistas, PiP y AirPlay: nada de eso se reimplementa, porque desde el punto de vista de AVPlayer no está pasando nada raro.

Dos cosas no se pueden reempaquetar y reciben su propio trato. Los subtítulos que son imágenes de texto en vez de texto (los PGS de los remux de Blu-ray) los lee el OCR de Vision en el propio dispositivo y se suman como subtítulos normales. Y un puñado de códecs que Apple no descodifica en absoluto — VP9, MPEG-2, VC-1 — toman una segunda vía en la que PrismCore descodifica y dibuja la imagen por su cuenta: ahí se pierde la interfaz del reproductor del sistema, pero la película se ve.

Lo que suele preguntarse

¿Recodifica mis archivos?

No. La imagen y el sonido se copian exactamente tal y como se leyeron; lo único que cambia es la caja en la que van. El archivo tampoco se modifica: PrismCore solo lo lee.

¿Y por qué AVPlayer no abre un MKV por sí solo?

Apple da soporte a una lista fija de contenedores y MKV no está en ella, incluso cuando el vídeo y el audio de dentro son formatos que Apple descodifica perfectamente. Es un problema de envoltorio, no de descodificación, y por eso basta con reempaquetar para resolverlo.

¿Qué pasa con el audio TrueHD o DTS?

La pila de Apple no los acepta como bitstream, así que no pueden pasar intactos. En lugar de reducirlos a estéreo, PrismCore los convierte a EAC3 con todos los canales en su sitio: el surround sigue siendo surround. Lo único que no sobrevive al viaje es el Atmos que va dentro de TrueHD; el Atmos en EAC3, que es el que llevan la mayoría de los remux, pasa sin tocarse.

¿Tiene que transcodificar mi servidor de Plex o Jellyfin?

No, y en eso está buena parte del sentido. El servidor envía el archivo original y el reempaquetado ocurre en tu dispositivo: no hay transcodificación en el servidor que funda un NAS, ni calidad perdida en ella.

¿Se puede desactivar?

Sí — Ajustes ▸ Reproducción en Aether. Está activo por defecto; si lo desactivas, la reproducción vuelve a los otros motores igual que antes, para esa instalación y sin reinstalar ni restablecer nada.

¿Tarda más en empezar?

No. La fuente se abre una sola vez y solo se lee su cabecera: decenas de milisegundos en un archivo local y en torno a una décima de segundo por red — verás «Preparando» más o menos lo mismo que con un archivo que Apple abre directamente.

Para desarrolladores

Todo lo que sigue trata de meter el motor en tu propia app. Si has venido como espectador, ya tienes la historia completa: el resto es fontanería.

De qué se encarga

Contenedores y códecs

Todo lo que libavformat sepa leer — MKV, MPEG-TS, AVI. HEVC, H.264 y AV1 pasan por copia de flujo directamente, junto con AAC, AC3, EAC3, FLAC y ALAC. TrueHD, DTS, Opus y el resto pasan por el puente de audio y llegan como EAC3 en vez de aplanarse. Una fuente anamórfica conserva la forma que declara su contenedor, en la caja pasp que AVPlayer respeta.

Dolby Atmos, no una mezcla reducida

El EAC3+JOC se copia intacto y nunca se descodifica a PCM — y la caja dec3 que FFmpeg pierde en una copia de flujo se vuelve a colocar: la única señal que hace que AVFoundation tome la vía Dolby en lugar de un DD+ corriente. Verificado en un receptor por HDMI.

Dolby Vision y HDR

El Profile 5 conserva su entrada dvh1, el Profile 7 se convierte en 8.1 de una sola capa mediante libdovi, y en tvOS el panel se programa antes de que AVPlayer vea siquiera la lista — el intercambio debe ocurrir primero o la variante se rechaza sin más. Un master que un televisor rechaza se reintenta sin esa declaración en vez de fallar.

Cada pista y cada subtítulo

Cada pista de audio se convierte en una rendition alternativa con su nombre, idioma y número de canales, así que el menú de pistas de AVKit funciona sin más. Los subtítulos de texto pasan a WebVTT segmentado que sobrevive a PiP y AirPlay; los PGS y VOBSUB solo llevan mapas de bits, así que los lee el OCR de Vision en el propio dispositivo y se suman como renditions normales — una pista no hace nada hasta que un reproductor la pide de verdad, y por eso un remux con decenas de pistas PGS no cuesta nada.

Saltar como en un archivo local

Un plan de segmentos alineado con fotogramas clave se publica antes del primer paquete, y un salto fuera de la ventana producida reancla el demultiplexor cuando hace falta. Una caché con presupuesto de bytes limita el disco, no la capacidad de saltar: los segmentos desalojados simplemente se vuelven a producir, y un segmento que se está sirviendo nunca es el desalojado. La producción se mantiene alrededor de un minuto por delante del último segmento que el reproductor pidió de verdad, así que un archivo de varios gigabytes nunca compite con su propia caché — y la lectura de la fuente se asienta en el bitrate real de la película en lugar de la velocidad de la línea. Un contenedor sin índice propio no se queda así: la primera reproducción secuencial recoge cada fotograma clave que lee y guarda el mapa, de modo que la siguiente planifica sobre él desde el primer segundo. Ese mismo mapa responde a SeekPreviewService, que descodifica el fotograma clave que cubre cualquier posición en una miniatura para la barra de avance del propio host.

Una vía por software para el resto

Los códecs que AVPlayer no descodifica en absoluto — VP9, MPEG-2, VC-1 — pasan por libavcodec a un AVSampleBufferDisplayLayer, sin copias allí donde VideoToolbox tiene descodificador por hardware. El AV1 pregunta al silicio real, no al nombre del chip, y las fuentes entrelazadas verificadas dejan la vía nativa para el desentrelazador — en la GPU, sobre los fotogramas que el descodificador ya produjo, si la compilación de FFmpeg trae ese filtro.

Un arranque rápido

Una reproducción abría su fuente dos veces — una para la decisión de enrutado del host y otra para producir — y por red esa segunda apertura es un viaje completo dentro de la espera que el usuario está mirando. Ahora la sonda entrega su contexto abierto a la sesión, cada apertura lee solo lo que necesita un contenedor que se describe a sí mismo, y las esperas internas se comprueban cada 10 ms en vez de cada 100. Un remux HEVC/EAC3 de 5,4 GB por HTTP va de la sonda a la lista en unos 135 ms en lugar de 520 — y un archivo sin índice de búsqueda, que si no habría que recorrer durante un minuto, arranca igualmente con un plan acotado.

Una licencia que funciona en la App Store

LGPL-2.1-or-later con una Application Store Exception. Una app firmada no puede permitir que nadie la vuelva a enlazar, lo que ponía en tensión la LGPL pura y la distribución en tienda; la excepción levanta ese único requisito para las compilaciones de tienda, mientras que las modificaciones de PrismCore siguen siendo LGPL y hay que publicarlas. La API pública es estable desde la 1.0 — una ruptura implica versión mayor, y cada versión queda anotada en el changelog.

Cómo se compara

En las plataformas de Apple se suele elegir entre un reproductor que conserva lo bueno pero solo abre los contenedores de Apple, y otro que lo abre todo pero dibuja sus propios fotogramas y descodifica el audio a PCM — justo donde mueren el Atmos y el Dolby Vision. PrismCore no es un reproductor: alimenta a AVPlayer, así que no hay nada que ceder.

PrismCoreAVPlayerVLCKitlibmpv
Reproduce MKV, MPEG-TS, AVI
Dolby Atmos pasado como bitstream
Dolby Vision activado en la pantalla
Match Content en tvOS — frecuencia y rango
La interfaz del reproductor de Apple: pistas, PiP, AirPlay
VP9, MPEG-2 y VC-1

VLCKit y libmpv dibujan en su propia capa y te entregan PCM, y por eso las filas centrales no les salen — es la consecuencia de poseer la vía de renderizado, no un descuido. AVPlayer falla en la primera y la última fila porque solo acepta contenedores para los que Apple da soporte.

Empezar

Añade el paquete y pásale una URL. Un único punto de entrada sondea la fuente y devuelve o bien una lista para AVPlayer, o bien una tubería por software ya arrancada.

.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()
}

Cuando la primera reproducción ya funciona, hay dos opciones que merecen conocerse. Dale a la sesión un directorio de caché y un contenedor sin índice propio se hace uno mientras suena: la siguiente reproducción se recorre como un archivo indexado. Ese mismo directorio sostiene las miniaturas de la barra de avance, que son su propia tubería pequeña — contexto aparte, descodificación en la CPU, caché por fotograma clave — así que nunca frenan la reproducción a la que pertenecen, con cualquier motor en pantalla.

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)

Las versiones mínimas son iOS 16, tvOS 17, macOS 14 y visionOS 1. FFmpeg llega mediante los xcframeworks dinámicos de MPVKit, así que un host que ya incluya MPVKit no añade dependencias binarias nuevas. Si tu CI resuelve las dependencias por ti, fija una versión exacta y mantén el Package.resolved del repositorio al mismo nivel — si no, una compilación en dispositivo y otra de TestFlight acabarán funcionando en silencio con motores distintos.

¿Solo quieres ver algo?

Esa era la mitad para desarrolladores de la página. Si has venido a ver tus propias películas y series, PrismCore ya está haciendo su trabajo dentro de Aether — nunca tendrás que pensar en él.

Ver Aether

PrismCore lo construye Václav Zmrhal · zmrhal.cz