You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
333 lines
15 KiB
333 lines
15 KiB
# Raspberry Pi NDI Gateway
|
|
|
|
**Work in Progress – erste öffentliche Veröffentlichung**
|
|
|
|
Ein Installationsskript für einen Raspberry Pi 4 (ARM64) mit Raspberry Pi OS / Debian 13 „Trixie“. Das Projekt richtet einen headless NDI-Gateway mit GStreamer ein:
|
|
|
|
- USB-HDMI-Capture → NDI
|
|
- NDI → HDMI über DRM/KMS
|
|
- optionales Capture-Audio → NDI
|
|
|
|
Der aktuelle Stand ist ausdrücklich **nicht** als vollständig getestete oder produktionsreife Lösung zu verstehen. Siehe [Bekannte Einschränkungen](#bekannte-einschränkungen).
|
|
|
|
## Funktionsumfang des aktuellen Skripts
|
|
|
|
| Bereich | Implementierter Stand |
|
|
|---|---|
|
|
| Betriebssystem | Debian 13 / Raspberry Pi OS Trixie, ARM64 |
|
|
| GStreamer | Debian-/Raspberry-Pi-OS-Systempakete |
|
|
| NDI-Plugin | `gst-plugin-ndi` aus `gst-plugins-rs`, standardmäßig Tag `0.14.5` |
|
|
| NDI-Runtime | Vorhandene NDI-6-Runtime wird gesucht; andernfalls wird ein SDK-Archiv benötigt |
|
|
| Capture-Video | Automatische oder manuelle V4L2-Geräteauswahl |
|
|
| Capture-Formate | MJPEG und YUYV, sofern vom Gerät angeboten |
|
|
| Capture-Audio | Optional; automatische oder manuelle ALSA-Geräteauswahl |
|
|
| NDI-Empfang | NDI-Quelle per Name oder direkter IP:Port-Adresse |
|
|
| HDMI-Video | Direkte Ausgabe über `kmssink` / DRM-KMS, ohne Desktop |
|
|
| HDMI-Audio | **Noch nicht implementiert**; empfangenes NDI-Audio wird aktuell verworfen |
|
|
| Dienste | `ndi-capture.service` und `ndi-display.service` |
|
|
| Diagnose | `/opt/ndi-pi/bin/ndi-pi-diagnose` |
|
|
|
|
## Architektur
|
|
|
|
### Capture: USB-Capture → NDI
|
|
|
|
```text
|
|
USB-HDMI-Capture
|
|
├── V4L2-Video
|
|
│ ├── MJPEG → jpegdec ───────────┐
|
|
│ └── YUYV → videoconvert ───────┤
|
|
│ ▼
|
|
│ kurze Queue
|
|
│ │
|
|
└── USB-Audio → ALSA → convert/resample
|
|
│
|
|
▼
|
|
ndisinkcombiner
|
|
│
|
|
ndisink
|
|
│
|
|
NDI OUT
|
|
```
|
|
|
|
Wenn kein passendes Capture-Audiogerät gefunden wird oder `ENABLE_AUDIO=false` gesetzt ist, wird eine Video-only-Pipeline gestartet. Die Audiozuordnung erfolgt anhand des USB-Gerätepfads; wenn keine eindeutige Übereinstimmung gefunden wird, kann derzeit ersatzweise das erste gefundene USB-Audiogerät gewählt werden.
|
|
|
|
### Display: NDI → HDMI
|
|
|
|
```text
|
|
NDI IN
|
|
│
|
|
ndisrc
|
|
│
|
|
ndisrcdemux
|
|
│
|
|
├── Video → queue → videoscale → kmssink → HDMI
|
|
│
|
|
└── Audio → queue → fakesink (wird verworfen)
|
|
```
|
|
|
|
Die Videoausgabe verwendet DRM/KMS und benötigt daher keine Desktop-Umgebung wie X11 oder Wayland. Wenn die Live-Pipeline beendet wird, versucht der Dienst einen schwarzen Standby-Bildschirm mit Statusanzeige zu starten und die NDI-Verbindung erneut aufzubauen.
|
|
|
|
## Voraussetzungen
|
|
|
|
- Raspberry Pi 4 mit 64-Bit-ARM-System
|
|
- Raspberry Pi OS / Debian 13 „Trixie“
|
|
- Netzwerkverbindung; Ethernet wird empfohlen
|
|
- USB-HDMI-Capture-Gerät mit Linux-V4L2-Unterstützung
|
|
- HDMI-Display am Pi für die lokale Ausgabe
|
|
- NDI-kompatible Gegenstelle im Netzwerk
|
|
- Root-/sudo-Rechte für die Installation
|
|
|
|
Das Skript prüft Architektur und Debian-Codename. Andere Raspberry-Pi-Modelle, Betriebssystemversionen oder 32-Bit-Systeme sind nicht als unterstützt anzusehen.
|
|
|
|
## Installation
|
|
|
|
1. Repository auf dem Raspberry Pi klonen.
|
|
2. Ein offizielles NDI-SDK-Archiv lokal bereitstellen oder eine Download-URL angeben.
|
|
3. Installationsskript mit Root-Rechten ausführen.
|
|
|
|
Beispiel mit lokal heruntergeladenem SDK-Archiv:
|
|
|
|
```bash
|
|
sudo NDI_SDK_TARBALL=/pfad/zum/ndi-sdk.tar.gz ./install-trixie-ndi-pi-v18.sh
|
|
```
|
|
|
|
Alternativ kann die URL über die Umgebungsvariable übergeben werden:
|
|
|
|
```bash
|
|
sudo NDI_SDK_URL="https://<NDI-SDK-Download-URL>" ./install-trixie-ndi-pi-v18.sh
|
|
```
|
|
|
|
`<NDI-SDK-Download-URL>` ist durch die aktuelle Download-URL des NDI-Herstellers zu ersetzen. Die URL ist absichtlich nicht im Skript fest hinterlegt.
|
|
|
|
Wenn die NDI-6-Runtime bereits an einem der vom Skript geprüften Orte installiert ist, wird kein SDK-Archiv benötigt:
|
|
|
|
- `/usr/local/lib`
|
|
- `/usr/lib/aarch64-linux-gnu`
|
|
|
|
Das Skript installiert Systemabhängigkeiten, baut das NDI-GStreamer-Plugin und legt Konfiguration, Hilfsskripte und systemd-Units an. Es aktiviert und startet anschließend beide Dienste.
|
|
|
|
> **Hinweis:** Das Installationsskript sollte vor dem Einsatz geprüft werden. Es verändert Systempakete, installiert Bibliotheken und schreibt Dateien unter `/opt/ndi-pi`, `/etc` und `/etc/systemd/system`.
|
|
|
|
## Warum GStreamer aus den Distributionspaketen kommt
|
|
|
|
GStreamer selbst wird nicht aus einem Git-Repository gebaut. Das Skript installiert die GStreamer-Komponenten aus den Debian-/Raspberry-Pi-OS-Paketen. Das zusätzliche NDI-Plugin wird separat aus `gst-plugins-rs` gebaut.
|
|
|
|
Standardmäßig verwendet das Skript den Tag `0.14.5`:
|
|
|
|
```text
|
|
Debian / Raspberry Pi OS GStreamer
|
|
│
|
|
└── gst-plugin-ndi (gst-plugins-rs 0.14.5)
|
|
│
|
|
└── NDI 6 Runtime
|
|
```
|
|
|
|
Der Plugin-Tag kann über `NDI_GST_TAG` überschrieben werden:
|
|
|
|
```bash
|
|
sudo NDI_GST_TAG=0.14.5 NDI_SDK_TARBALL=/pfad/zum/ndi-sdk.tar.gz ./install-trixie-ndi-pi-v18.sh
|
|
```
|
|
|
|
## Konfiguration
|
|
|
|
Die zentrale Konfigurationsdatei lautet:
|
|
|
|
```text
|
|
/etc/ndi-pi.conf
|
|
```
|
|
|
|
Eine neue Installation legt sie mit folgenden wesentlichen Standardwerten an:
|
|
|
|
```ini
|
|
PI_NAME=<HOSTNAME>
|
|
NDI_CAPTURE_NAME=<HOSTNAME>-Capture
|
|
NDI_DISPLAY_SOURCE=PC01-Capture
|
|
NDI_DISPLAY_ADDRESS=auto
|
|
NDI_USE_DIRECT_ADDRESS=true
|
|
|
|
CAPTURE_DEVICE=auto
|
|
CAPTURE_WIDTH=1920
|
|
CAPTURE_HEIGHT=1080
|
|
CAPTURE_FPS=30
|
|
CAPTURE_FORMAT=MJPEG
|
|
CAPTURE_AUTO_FALLBACK=true
|
|
CAPTURE_QUEUE_BUFFERS=2
|
|
|
|
ENABLE_AUDIO=true
|
|
CAPTURE_AUDIO_DEVICE=auto
|
|
CAPTURE_AUDIO_RATE=48000
|
|
CAPTURE_AUDIO_CHANNELS=2
|
|
|
|
ENABLE_HDMI_AUDIO=false
|
|
HDMI_AUDIO_DEVICE=auto
|
|
KMS_DRIVER=vc4
|
|
KMS_CONNECTOR_ID=auto
|
|
|
|
NDI_MAX_QUEUE=0
|
|
DISPLAY_WIDTH=1920
|
|
DISPLAY_HEIGHT=1080
|
|
DISPLAY_FPS=60
|
|
```
|
|
|
|
`<HOSTNAME>` steht hier nur als Platzhalter für den vom Installer ermittelten Hostnamen. Die tatsächliche Datei enthält konkrete Werte.
|
|
|
|
### Wichtige Einstellungen
|
|
|
|
| Einstellung | Bedeutung |
|
|
|---|---|
|
|
| `NDI_CAPTURE_NAME` | Name der vom Pi gesendeten NDI-Quelle |
|
|
| `NDI_DISPLAY_SOURCE` | Name der NDI-Quelle, die der Pi empfangen soll |
|
|
| `NDI_DISPLAY_ADDRESS` | `auto` für mDNS-Auflösung oder feste Adresse im Format `IP:Port` |
|
|
| `NDI_USE_DIRECT_ADDRESS` | Bei `true` wird die aufgelöste bzw. konfigurierte IP:Port-Adresse für `ndisrc` verwendet |
|
|
| `CAPTURE_DEVICE` | `auto` oder ein konkreter V4L2-Gerätepfad |
|
|
| `CAPTURE_WIDTH`, `CAPTURE_HEIGHT`, `CAPTURE_FPS` | Bevorzugter Capture-Modus |
|
|
| `CAPTURE_FORMAT` | `MJPEG`, `YUYV` oder `auto` |
|
|
| `CAPTURE_AUTO_FALLBACK` | Erlaubt die Suche nach einem anderen unterstützten Modus |
|
|
| `CAPTURE_QUEUE_BUFFERS` | Anzahl der Videobuffer in der Capture-Queue |
|
|
| `ENABLE_AUDIO` | Aktiviert/deaktiviert Capture-Audio → NDI |
|
|
| `CAPTURE_AUDIO_DEVICE` | `auto` oder ALSA-Gerät, z. B. `plughw:2,0` |
|
|
| `KMS_DRIVER` | DRM/KMS-Treiber, Standard `vc4` |
|
|
| `KMS_CONNECTOR_ID` | `auto` oder eine feste DRM-Connector-ID |
|
|
| `DISPLAY_WIDTH`, `DISPLAY_HEIGHT`, `DISPLAY_FPS` | Auflösung und Framerate des Standby-Bildes |
|
|
| `NDI_MAX_QUEUE` | NDI-Empfangsqueue; Standardwert `0` |
|
|
|
|
`ENABLE_HDMI_AUDIO` und `HDMI_AUDIO_DEVICE` sind derzeit vorbereitete Konfigurationswerte, werden von der aktuellen Display-Pipeline aber **noch nicht umgesetzt**. Sie einzuschalten aktiviert daher keine HDMI-Audioausgabe.
|
|
|
|
Bestehende Konfigurationen werden vom Installer ergänzt, ohne vorhandene Werte generell zu überschreiben. Bei älteren Konfigurationsdateien sollten die benötigten Capture-Werte kontrolliert und gegebenenfalls ergänzt werden.
|
|
|
|
## Capture-Geräteauswahl und Videoformate
|
|
|
|
Mit:
|
|
|
|
```ini
|
|
CAPTURE_DEVICE=auto
|
|
```
|
|
|
|
untersucht das Skript `/dev/video*` und berücksichtigt Geräte mit V4L2-Video-Capture-Funktion und einem unterstützten Modus.
|
|
|
|
Für eine feste Installation kann ein konkreter Pfad eingetragen werden, vorzugsweise ein stabiler Symlink:
|
|
|
|
```ini
|
|
CAPTURE_DEVICE=/dev/v4l/by-id/<GERAETEPFAD>
|
|
```
|
|
|
|
Die Modusauswahl berücksichtigt die tatsächlich vom Gerät gemeldeten Formate. Die gewünschte Kombination aus Auflösung und Framerate wird zuerst versucht. Wenn `CAPTURE_AUTO_FALLBACK=true` gesetzt ist, folgt eine festgelegte Fallback-Liste.
|
|
|
|
**Wichtig zur Formatpriorität:** Bei `CAPTURE_FORMAT=auto` ist die aktuelle Fallback-Reihenfolge YUYV vor MJPEG. Auch die Gerätebewertung bevorzugt YUYV. Das unterscheidet sich von einer MJPEG-first-Strategie. Bei einer neuen Installation steht `CAPTURE_FORMAT=MJPEG` als Standard in der Konfiguration; damit wird die Auswahl auf MJPEG beschränkt, sofern ein passender Modus vorhanden ist und ein Fallback nicht durch die Formatvorgabe ausgeschlossen wird.
|
|
|
|
MJPEG wird mit `jpegdec` dekodiert. Der aktuelle Code verwendet bewusst nicht `v4l2jpegdec`. YUYV wird über `videoconvert` in UYVY konvertiert, bevor es an den NDI-Sink geht.
|
|
|
|
## Audio
|
|
|
|
### Capture-Audio → NDI
|
|
|
|
Bei `ENABLE_AUDIO=true` versucht das Skript, ein ALSA-Gerät zu finden, das zum ausgewählten USB-Capture-Gerät gehört. Alternativ kann ein ALSA-Gerät fest vorgegeben werden:
|
|
|
|
```ini
|
|
CAPTURE_AUDIO_DEVICE=plughw:2,0
|
|
```
|
|
|
|
Die automatische Zuordnung ist heuristisch und sollte mit der konkreten Capture-Hardware überprüft werden. Wird kein Gerät gefunden, startet die Capture-Pipeline als Video-only.
|
|
|
|
### NDI-Audio → HDMI
|
|
|
|
Diese Richtung ist im aktuellen Skript **noch nicht implementiert**. Der Audio-Pad von `ndisrcdemux` wird derzeit an `fakesink` angeschlossen und damit verworfen. Es gibt aktuell keine ALSA-Wiedergabepipeline für den NDI-Ton.
|
|
|
|
## NDI-Discovery und Netzwerk
|
|
|
|
Der Display-Dienst verwendet standardmäßig:
|
|
|
|
```ini
|
|
NDI_DISPLAY_SOURCE=PC01-Capture
|
|
NDI_DISPLAY_ADDRESS=auto
|
|
NDI_USE_DIRECT_ADDRESS=true
|
|
```
|
|
|
|
Bei `auto` versucht das Skript, den NDI-Dienst über Avahi/mDNS (`_ndi._tcp`) aufzulösen und die ermittelte IP-Adresse samt Port an `ndisrc` zu übergeben. Eine feste Adresse kann so angegeben werden:
|
|
|
|
```ini
|
|
NDI_DISPLAY_ADDRESS=192.168.1.50:5961
|
|
```
|
|
|
|
Der tatsächliche Port ist abhängig von der NDI-Quelle und muss passend ermittelt werden. Wenn keine direkte Adresse verfügbar ist, verwendet der initiale Start `ndi-name` als Fallback. Die Wiederverbindungslogik ist derzeit noch eingeschränkt; siehe [Bekannte Einschränkungen](#bekannte-einschränkungen).
|
|
|
|
Für Discovery über VLAN- oder Subnetzgrenzen hinweg kann eine gesonderte NDI-Discovery-Server-Konfiguration erforderlich sein. Das wird vom Installationsskript nicht eingerichtet.
|
|
|
|
## systemd-Dienste und Logs
|
|
|
|
Es werden zwei getrennte Dienste angelegt:
|
|
|
|
```text
|
|
ndi-capture.service
|
|
ndi-display.service
|
|
```
|
|
|
|
Status prüfen:
|
|
|
|
```bash
|
|
systemctl status ndi-capture
|
|
systemctl status ndi-display
|
|
```
|
|
|
|
Logs verfolgen:
|
|
|
|
```bash
|
|
journalctl -u ndi-capture -f
|
|
journalctl -u ndi-display -f
|
|
```
|
|
|
|
Beide Dienste verwenden `Restart=always` und aktuell `RestartSec=1`.
|
|
|
|
Nach einer Änderung an `/etc/ndi-pi.conf`:
|
|
|
|
```bash
|
|
sudo systemctl restart ndi-capture ndi-display
|
|
```
|
|
|
|
## Diagnose
|
|
|
|
Das Diagnoseprogramm liegt unter:
|
|
|
|
```bash
|
|
sudo /opt/ndi-pi/bin/ndi-pi-diagnose
|
|
```
|
|
|
|
Es sammelt unter anderem:
|
|
|
|
- Kernel- und Betriebssysteminformationen
|
|
- GStreamer-Version und ausgewählte Plugin-Informationen
|
|
- V4L2-Geräte und gemeldete Capture-Formate
|
|
- ALSA-Aufnahme- und Wiedergabegeräte
|
|
- DRM-Geräte und Connector-Status
|
|
- NDI-Konfiguration und NDI/mDNS-Discovery
|
|
- systemd-Status und letzte Service-Logs
|
|
|
|
Für Fehlerberichte ist die vollständige Ausgabe hilfreich. Zugangsdaten oder andere private Netzwerkinformationen sollten vor dem Veröffentlichen entfernt werden.
|
|
|
|
## Bekannte Einschränkungen
|
|
|
|
Der folgende Abschnitt beschreibt bewusst den Stand des aktuellen Skripts und ist Teil der WIP-Kennzeichnung.
|
|
|
|
1. **NDI-Audio wird am HDMI-Ausgang nicht wiedergegeben.** Der Empfangs-Audiozweig endet aktuell in `fakesink`.
|
|
2. **Automatische USB-Audiozuordnung ist nicht garantiert.** Wenn die Zuordnung zum Video-Gerät nicht gelingt, kann ein anderes erstes USB-Audiogerät als Fallback ausgewählt werden.
|
|
3. **Wiederverbindung nach NDI-Ausfall ist eingeschränkt.** Die Standby-Schleife prüft eine direkte IP:Port-Adresse. Wenn nur der Namens-Fallback aktiv ist oder mDNS die Quelle nicht auflösen kann, wird die Quelle nicht in allen Fällen erneut gefunden.
|
|
4. **Signalbehandlung des Display-Helfers muss weiter getestet werden.** Das aktuelle Trap räumt den Standby-Prozess auf; das Verhalten beim Beenden durch systemd sollte auf dem Zielgerät überprüft werden.
|
|
5. **Ältere Konfigurationsdateien benötigen Prüfung.** Die Migration ergänzt einige Schlüssel, aber nicht alle möglichen Capture-Parameter. Fehlende Werte wie `CAPTURE_WIDTH` oder `CAPTURE_FPS` können bei älteren Konfigurationen problematisch sein.
|
|
6. **NDI-Runtime-Pfad in systemd:** Der Installer erkennt die Runtime auch unter `/usr/lib/aarch64-linux-gnu`; die erzeugten systemd-Units setzen aktuell jedoch fest `NDI_RUNTIME_DIR_V6=/usr/local/lib`. Bei einer Runtime-Installation im Multiarch-Verzeichnis muss das geprüft werden.
|
|
7. **Keine vollständige Hardware-/Laufzeitvalidierung durch Syntaxprüfung:** Ein erfolgreicher Bash-Syntaxcheck bestätigt weder GStreamer-Pipeline-Negotiation noch NDI-Discovery, DRM/KMS-Ausgabe oder das Verhalten einer konkreten Capture-Karte.
|
|
|
|
Weitere bekannte Entwicklungsaufgaben sind eine umfassendere Plugin-Prüfung, robustere Installer-Rollback-Strategien und eine Prüfung des SDK-Archivs anhand eines verifizierten Hashes bzw. einer Signatur.
|
|
|
|
## Sicherheit und Lizenzhinweise
|
|
|
|
Das NDI SDK bzw. die NDI-Runtime wird vom NDI-Hersteller bereitgestellt und unterliegt dessen Lizenz- und Distributionsbedingungen. Das SDK-Archiv und die Runtime-Bibliotheken sollten nicht ohne Prüfung dieser Bedingungen in ein öffentliches Repository eingecheckt oder weiterverteilt werden.
|
|
|
|
Das Repository enthält das Installationsskript und die Projektdateien; Nutzer müssen die NDI-Runtime entsprechend den geltenden Herstellerbedingungen selbst beziehen bzw. bereitstellen.
|
|
|
|
Das Installationsskript entpackt ein bereitgestelltes SDK-Archiv mit Root-Rechten. Verwende nur ein vertrauenswürdiges Archiv aus einer offiziellen Quelle. Eine automatisierte Hash-/Signaturprüfung des Archivs ist im aktuellen Skript noch nicht implementiert.
|
|
|
|
## Projektstatus
|
|
|
|
Dieses Projekt wird aktiv entwickelt. Hardwarekombinationen, Capture-Modi, NDI-Versionen und HDMI-Ausgabeverhalten können sich unterscheiden. Rückmeldungen mit Diagnoseausgabe, Pi-Modell, OS-Version und genauer Capture-Hardware sind willkommen.
|
|
|
|
**Vor einem produktiven Einsatz sind Tests mit der eigenen Hardware und Netzwerkinfrastruktur erforderlich.**
|
|
|