Verzögerungsfreier lokaler Medienserver: Jellyfin auf Raspberry Pi 5 mit Hardware-Beschleunigung
Teil 5 von 5 der Reihe Homelab auf dem Raspberry Pi

Inhalt
Architektur-Überblick: Mediendekodierung auf dem Raspberry Pi 5
Das Hosting eines selbstverwalteten Video-Streaming-Servers auf einem Raspberry Pi war historisch oft durch Leistungsenzpässe bei der Echtzeit-Transkodierung limitiert. Nicht unterstützte Codecs, inkompatible Tonspuren oder begrenzte Netzwerkbandbreiten zwingen den Medienserver dazu, Videobilder zur Laufzeit zu dekodieren und neu zu kodieren. Auf generischen ARM-Prozessorkernen führt die rein softwarebasierte Transkodierung von hochauflösenden HEVC-(H.265-) oder 4K-Dateien schnell zur Auslastung der CPU, was thermisches Drosseln und Ruckeln beim Abspielen verursacht.
Der Raspberry Pi 5 (basierend auf dem Broadcom-BCM2712-SoC) dekodiert in Hardware allein HEVC, und dieser Decoder ist zustandslos: Er wird über die V4L2-Request-API angesprochen, nicht über zustandsbehaftete V4L2-M2M-Decoder wie hevc_v4l2m2m. Jellyfin nutzt ihn nicht: Die Option „Video4Linux2“ setzt allein V4L2-Encoder wie h264_v4l2m2m ein, und einen Encoder hat der Pi 5 nicht; die V4L2-Unterstützung für den Raspberry Pi hat das Projekt zudem abgekündigt. Als Container betrieben, dekodiert und kodiert Jellyfin auf dem Pi 5 deshalb in Software auf den vier ARM-Cortex-A76-Kernen; ein niedriger Stromverbrauch gilt für Direct Play und nicht für das Transkodieren.

Schritt-für-Schritt-Implementierungsanleitung
Schritt 1: Betriebssystem-Vorbereitung und Prüfung der DRM-Geräteanbindung
Eine 64-Bit-Installation von Raspberry Pi OS Lite ist erforderlich, um die Kompatibilität mit den 64-Bit-FFmpeg-Hardwarebibliotheken zu gewährleisten; aktuelle Images basieren seit Oktober 2025 auf Debian 13 (Trixie), Debian 12 (Bookworm) gilt als Mindestversion. Vor der Einrichtung der Container-Laufzeitumgebung muss das Vorhandensein der Direct-Rendering-Manager-(DRM-)Schnittstellen im Terminal überprüft werden:
ls -l /dev/dri
Eine funktionsfähige Systemausgabe zeigt die Grafikkarten- und Render-Knoten (card0, card1, renderD128) an. Damit Docker-Container auf diese Grafikknoten zugreifen dürfen, muss die korrekte Gruppenzugehörigkeit konfiguriert sein:
sudo usermod -aG video,render "$USER"
Schritt 2: NVMe-Speicheranbindung und Verzeichnisstruktur
Für schnelle Bibliotheksscans und reibungslose Datenübertragungsraten sollten die Mediendateien auf einer NVMe-SSD (über PCIe 2.0/3.0) oder auf einem UASP-fähigen USB-3.0-Speichersystem liegen. Unter /opt/containers/jellyfin/ wird eine strukturierte Ordnerhierarchie erstellt:
mkdir -p /opt/containers/jellyfin/{config,cache}
mkdir -p /mnt/media/{movies,series}
chmod -R 755 /mnt/media
Schritt 3: Konfiguration des deklarativen Docker-Compose-Stacks
Die Container-Orchestrierung wird in der Datei /opt/containers/jellyfin/docker-compose.yml konfiguriert. Das Host-Verzeichnis /dev/dri, das eine Hardwarebeschleunigung bräuchte, wird in den Container gemappt, auf dem Pi 5 nur vorsorglich (siehe Schritt 4); der Container-Prozess läuft über user unter einer festen Benutzer-ID und tritt über group_add zusätzlich den Host-Gruppen render und video anhand ihrer numerischen GIDs bei:
services:
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
restart: unless-stopped
user: "1000:1000"
group_add:
- "44" # Durch die numerische Host-GID der Gruppe 'video' ersetzen
- "109" # Durch die numerische Host-GID der Gruppe 'render' ersetzen
network_mode: "host"
environment:
- JELLYFIN_PublishedServerUrl=http://jellyfin.lukaswojcik.com
volumes:
- "/opt/containers/jellyfin/config:/config"
- "/opt/containers/jellyfin/cache:/cache"
- "/mnt/media:/media:ro"
devices:
- "/dev/dri:/dev/dri"
security_opt:
- no-new-privileges:true
Technischer Hinweis: Der Einsatz von network_mode: "host" maximiert den Datendurchsatz im Netzwerk und ermöglicht die automatische DLNA-/UPnP-Geräteerkennung im Heimnetzwerk ohne komplexe Port-Forwarding-Regeln.
Schritt 4: Transkodierungseinstellungen im Jellyfin-Dashboard
Nach dem Start des Stacks mittels docker compose up -d wird die Transkodierung in der grafischen Administrationsoberfläche von Jellyfin eingestellt:
- Das Webinterface unter
http://<Raspberry-Pi-IP>:8096aufrufen und zu Dashboard → Wiedergabe → Transkodierung navigieren. - Im Dropdown-Menü für Hardwarebeschleunigung keine Beschleunigung auswählen. Video4Linux2 (V4L2) bringt auf dem Pi 5 nichts: Jellyfin verwendet darüber nur V4L2-Encoder, dem BCM2712 fehlt jeder Videoencoder, und die Jellyfin-Dokumentation führt V4L2 für den Raspberry Pi als abgekündigt. Einen Eintrag OpenMAX/OMX gibt es nicht mehr: Jellyfin hat ihn entfernt, und aus Raspberry Pi OS ist die OMX-Schnittstelle seit Bullseye verschwunden.
- Kontrollkästchen für eine Hardwaredekodierung sind damit nicht zu setzen. Den einzigen Hardware-Decoder des SoC, den für HEVC, spricht Jellyfin nicht an, und die H.264-, MPEG-2- und MPEG-4-Decoder des Raspberry Pi 4 fehlen dem BCM2712 ganz; alle Formate werden auf den Cortex-A76-Kernen in Software dekodiert.
- Den FFmpeg-Pfad auf
/usr/lib/jellyfin-ffmpeg/ffmpegfestlegen und die Konfiguration speichern.
Schritt 5: Qualitätssicherung und Audit der Echtzeit-Transkodierung
Wie stark das Transkodieren die CPU belastet und ob Jellyfin überhaupt neu kodiert, zeigt eine Überprüfung während eines aktiven Video-Streams:
- Transkodierten Stream starten: Eine HEVC-(H.265-)10-Bit-Videodatei im Webbrowser aufrufen, der kein natives H.265 unterstützt, um eine Transkodierung zu H.264 zu erzwingen. Dekodierung und Kodierung laufen dabei in Software: Jellyfin nutzt den HEVC-Decoder des Pi 5 nicht, und der BCM2712 enthält überhaupt keinen Videoencoder, das H.264-Encoding übernimmt libx264 auf der CPU.
- CPU-Auslastung im Terminal prüfen: In einer SSH-Sitzung auf dem Raspberry Pi das Tool
htopodertopausführen. Da Dekodierung und Kodierung in Software erfolgen, ist eine hohe Last auf allen vier Kernen in diesem Szenario zu erwarten und kein Zeichen einer fehlerhaften Einrichtung. Niedrige CPU-Werte ergeben sich erst ohne Neukodierung, also bei Direct Play. Dass der HEVC-Decoder selbst arbeitet, zeigt nur ein Dekodiertest außerhalb von Jellyfin mit dem FFmpeg aus Raspberry Pi OS auf dem Host, etwaffmpeg -hwaccel drm -i datei.mkv -f null -. - Transkodierungs-Logs analysieren: Die Logdateien unter
/opt/containers/jellyfin/config/log/ffmpeg-transcode-*.txtöffnen: Ein Decoder wiehevc_v4l2m2merscheint dort nicht, weil Jellyfin für V4L2 keinen Decoder setzt. Aufschlussreich ist der Eintrag hinter-codec:v:0:libx264steht für eine Neukodierung des Bildes,copyfür bloßes Umverpacken.
Zusammenfassung und resultierender Mehrwert
Was sich damit erreichen lässt: Die Bereitstellung eines containerisierten, selbstgehosteten Jellyfin-Medienservers auf einem Raspberry Pi 5, der Videodateien per Direct Play ausliefert und bei Bedarf in Software transkodiert.
Resultierender Mehrwert:
- Ruckelfreies lokales Medien-Streaming: Videodateien mit hoher Bitrate (inklusive HEVC-/H.265-Archiven) werden auf Endgeräten, die ihren Codec beherrschen, per Direct Play ohne Pufferzeiten oder Ladeverzögerungen abgespielt.
- Niedriger Energieverbrauch: Bei Direct Play liefert der Server die Datei aus, ohne sie zu dekodieren, der Stromverbrauch bleibt damit niedrig, was einen lautlosen und sparsamen 24/7-Dauerbetrieb ermöglicht; das Transkodieren mit libx264 lastet dagegen alle vier Kerne aus und verlangt aktive Kühlung.
- Volle Datensouveränität und Unabhängigkeit: Lokale Videosammlungen verbleiben zu 100 % im eigenen Netzwerk, ohne Cloud-Abhängigkeit, externe Telemetriedaten oder monatliche Abonnementkosten.
Fragen und Antworten
Warum transkodiert Jellyfin, obwohl das Endgerät HEVC abspielen kann?
Weil der Server nicht nur den Videocodec prüft. Eine Neukodierung des Bildes wird auch dann nötig, wenn ein anderer Teil der Datei nicht zum Endgerät passt, und auf dem Raspberry Pi 5 läuft jede solche Kodierung in Software. Häufige Auslöser sind:
- Untertitel in Bildformaten wie PGS, die das Endgerät nicht selbst darstellt. Sie werden in das Bild eingebrannt, und dafür muss das Video neu kodiert werden. Textuntertitel wie SRT lassen sich dagegen meist getrennt ausliefern.
- Eine Bitratengrenze im Abspieler, die unter der Bitrate der Datei liegt. Der Server rechnet dann auf eine kleinere Bitrate herunter, auch wenn der Codec passt.
- Eine Tonspur, die das Endgerät nicht unterstützt. Hier genügt oft, nur den Ton umzuwandeln, was die CPU weit weniger belastet als eine Neukodierung des Bildes.
Die Protokolle unter /config/log, die der Artikel für die Kontrolle nennt, zeigen, welcher Fall vorliegt: Steht dort für das Video copy statt libx264, wird die Datei nur umverpackt oder ihr Ton gewandelt. Wer die Ursachen beseitigt, etwa mit Textuntertiteln oder einer höheren Bitratengrenze im Abspieler, erreicht Direct Play und damit die niedrigen CPU-Werte, die der Artikel für diesen Fall nennt.
Warum stehen in group_add Zahlen und nicht die Gruppennamen video und render?
Der Kernel prüft die Rechte an /dev/dri anhand der numerischen Gruppen-ID, und die Namen video und render sind nur im Host-System an diese Nummern gebunden; im Image des Containers können sie fehlen oder andere Nummern tragen. Die richtigen Werte liefert auf dem Host der Befehl getent group video render. Das usermod aus Schritt 1 wirkt dagegen nur für den Benutzer auf dem Host, nicht für den Prozess im Container.
Braucht der Raspberry Pi 5 für diesen Aufbau eine aktive Kühlung?
Sobald er transkodiert, ja. Weil der BCM2712 keinen Videoencoder hat, lastet libx264 bei jeder Transkodierung alle vier Kerne aus, und das über die gesamte Länge eines Films. Ohne aktive Kühlung erreicht der SoC dabei die Temperatur, ab der die Firmware den Takt senkt, und genau dieses thermische Drosseln bringt das Ruckeln, das der Artikel für die Transkodierung in Software beschreibt.
Ob schon gedrosselt wurde, zeigt vcgencmd get_throttled auf dem Host: Der Wert 0x0 bedeutet, dass seit dem Start weder Unterspannung noch Drosselung aufgetreten ist. Wer überwiegend per Direct Play abspielt, kommt mit passiver Kühlung meist aus, weil dann weder dekodiert noch kodiert werden muss.
Homelab auf dem Raspberry Pi
- Raspberry Pi 4 und 5: Vom SSD-Laufwerk booten über den Bootloader
- Unterbrechungsfreie Stromversorgung (USV) für Raspberry Pi 4 und 5: Die Top 5 Lösungen für anspruchsvolle Setups
- Lokales CI/CD für den Raspberry Pi: Automatisierung von Docker-Compose-Deployments
- Autonomer Docker-Compose-Heimserver mit Traefik, SSL und Watchtower
- Verzögerungsfreier lokaler Medienserver: Jellyfin auf Raspberry Pi 5 mit Hardware-Beschleunigung