Claude: miese Auflösung
This commit is contained in:
109
doc/02_HardwareEncoding.md
Normal file
109
doc/02_HardwareEncoding.md
Normal file
@@ -0,0 +1,109 @@
|
||||
# Hardware-Encoding — Was, Warum, Wie
|
||||
|
||||
## Das Problem in einem Satz
|
||||
|
||||
go2rtc muss jeden Kamera-Frame von **MJPEG** (was die USB-Kamera liefert) in
|
||||
**H.264** umwandeln (was WebRTC im Browser braucht). Das macht standardmässig
|
||||
die **CPU** — und das frisst einen ganzen Kern (~100% für 2 Kameras).
|
||||
|
||||
---
|
||||
|
||||
## Was Hardware-Encoding bedeutet
|
||||
|
||||
Der ThinkCentre hat eine **Intel-iGPU** (integrierter Grafikchip) mit
|
||||
**Quick Sync Video** — ein dedizierter H.264-Encoder-Block auf dem Chip.
|
||||
|
||||
```
|
||||
Software-Encoding (bisher): MJPEG → libx264 (CPU) → H.264 → WebRTC
|
||||
Hardware-Encoding (neu): MJPEG → h264_vaapi (GPU) → H.264 → WebRTC
|
||||
```
|
||||
|
||||
Das Bild ist identisch — nur wer encodiert ändert sich.
|
||||
CPU-Last: ~100% → **~5–10%**. Latenz: unverändert.
|
||||
|
||||
---
|
||||
|
||||
## Warum VAAPI / renderD128
|
||||
|
||||
VAAPI (Video Acceleration API) ist die Linux-Schnittstelle zur GPU.
|
||||
Das Device `/dev/dri/renderD128` ist der GPU-Zugriffspunkt.
|
||||
|
||||
Bestätigt auf dem ThinkCentre:
|
||||
```
|
||||
crw-rw----+ 1 root render 226, 128 /dev/dri/renderD128 ✓ vorhanden
|
||||
```
|
||||
|
||||
FFmpeg greift via VAAPI auf den Intel Quick Sync Encoder zu.
|
||||
go2rtc wählt automatisch `h264_vaapi` wenn `#hardware` gesetzt und
|
||||
`/dev/dri` im Container verfügbar ist.
|
||||
|
||||
---
|
||||
|
||||
## Was sich im docker-compose ändert
|
||||
|
||||
**Zwei Zeilen** gegenüber der Software-Encoding-Variante:
|
||||
|
||||
```yaml
|
||||
# 1. GPU-Device in den Container durchreichen
|
||||
devices:
|
||||
- /dev/video0:/dev/video0
|
||||
- /dev/video2:/dev/video2
|
||||
- /dev/dri:/dev/dri # ← neu
|
||||
|
||||
# 2. #hardware am Ende der Stream-URL
|
||||
streams:
|
||||
cam0: "ffmpeg:device?video=/dev/video0&input_format=mjpeg&...#video=h264#hardware"
|
||||
# ^^^^^^^^
|
||||
```
|
||||
|
||||
go2rtc liest `#hardware` und wählt automatisch den VAAPI-Encoder.
|
||||
|
||||
---
|
||||
|
||||
## Erwartetes Ergebnis
|
||||
|
||||
| Messgrösse | Vorher (Software) | Nachher (Hardware) |
|
||||
|------------|-------------------|-------------------|
|
||||
| CPU go2rtc | ~100% | ~5–10% |
|
||||
| Latenz | ~130ms + Jitter | ~130ms, stabiler |
|
||||
| Freezes | gelegentlich (libx264 unter Last) | deutlich seltener |
|
||||
| Bandbreite | ~1.5 Mbps/Stream | ähnlich |
|
||||
| On-demand (0% CPU ohne Client) | ✓ | ✓ |
|
||||
|
||||
---
|
||||
|
||||
## Verifikation nach Neustart
|
||||
|
||||
```bash
|
||||
# 1. CPU-Last
|
||||
docker stats --no-stream --format "{{.Name}} {{.CPUPerc}}" AppRobotGo2RTC
|
||||
# Erwartet: <10% mit aktivem Stream
|
||||
|
||||
# 2. Codec im Log (h264_vaapi = Hardware aktiv)
|
||||
docker logs AppRobotGo2RTC 2>&1 | grep -E "vaapi|libx264|codec|encoder"
|
||||
|
||||
# 3. go2rtc Web-UI zeigt Stream
|
||||
# http://thinkcentre.local:1984/ → cam0 und cam1 sichtbar
|
||||
|
||||
# 4. Browser-Viewer
|
||||
# http://thinkcentre.local:8444/ → Bild, geringe Latenz
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Fallback
|
||||
|
||||
Falls `#hardware` nicht funktioniert (kein Bild, Codec-Fehler im Log):
|
||||
```yaml
|
||||
# In docker-compose.yaml, Kommentar-Zeile aktivieren:
|
||||
cam0: "ffmpeg:device?video=/dev/video0&input_format=mjpeg&video_size=640x480&framerate=30#video=h264"
|
||||
```
|
||||
Software-Encoding ohne `#hardware` — funktioniert immer, aber ~100% CPU.
|
||||
|
||||
---
|
||||
|
||||
## Nächste optionale Schritte
|
||||
|
||||
- **Hi-Res Snapshots**: `#hardware#video=mjpeg` hinzufügen für nativen JPEG-Snapshot-Track
|
||||
- **GOP-Grösse**: Keyframe-Abstand `-g 50` (1.67s) via MediaMTX-Zwischenstufe verkürzen
|
||||
- **Internet**: Caddy als Reverse Proxy mit TLS (Phase 4 in `01_WebcamRoadmap.md`)
|
||||
@@ -9,192 +9,173 @@ bleibt ein Einzelbild ganz stehen. Im reinen MJPEG-Modus trat das **nicht** auf.
|
||||
|
||||
## Diagnose-Verlauf
|
||||
|
||||
### Schritt 1 — CPU-Messung (erste Verdachtsphase)
|
||||
### Phase 1 — Messung und Eingrenzung
|
||||
|
||||
| Quelle | CPU |
|
||||
|--------|-----|
|
||||
| System gesamt | ~40 % |
|
||||
| AppRobotGo2RTC, 1 Client | **~35 %** |
|
||||
| AppRobotGo2RTC, 2 Clients (Laptop + Handy) | **65–114 %** |
|
||||
| AppRobotWebcam (Node.js) | **0 %** |
|
||||
| AppRobotGo2RTC, 1 Client | ~35–103 % |
|
||||
| AppRobotGo2RTC, 2 Clients | 65–114 % |
|
||||
| AppRobotWebcam (Node.js) | 0 % |
|
||||
| Browser-Client (Laptop) | ~10 % |
|
||||
|
||||
`docker stats` rechnet pro Kern: 114 % = mehr als ein Kern voll ausgelastet.
|
||||
`getStats()` im Browser lieferte konstant `recv=30/s decoded=30/s dropped=0/s` →
|
||||
Browser und Netz sind nicht das Problem.
|
||||
|
||||
**Erkenntnis:** go2rtc re-encodiert nicht einmal pro Stream, sondern aufwändiger
|
||||
pro Client-Verbindung (WebRTC-Session). Zwei Clients = fast doppelte CPU-Last.
|
||||
Zwei Browser (Laptop + Handy) zeigen exakt identische Latenz für cam0 bzw. cam1.
|
||||
Ändert sich die Latenz, ändert sie sich auf beiden Clients synchron →
|
||||
**Problem sitzt in go2rtc/FFmpeg, nicht in Netz oder Browser.**
|
||||
|
||||
### Schritt 2 — Browser-Client als Ursache ausgeschlossen
|
||||
### Phase 2 — Root-Cause-Analyse
|
||||
|
||||
WebRTC `getStats()` lieferte über mehrere Minuten:
|
||||
go2rtc's generierter FFmpeg-Befehl (simple URL-Form):
|
||||
```
|
||||
recv=30/s decoded=30/s dropped=0/s lost=+0 jitter=13–35ms
|
||||
```
|
||||
→ Server liefert alle Frames, Netz verliert nichts, Decoder schafft alles.
|
||||
**Der Browser ist nicht das Problem.**
|
||||
|
||||
### Schritt 3 — Netz als Ursache ausgeschlossen
|
||||
|
||||
Zwei Browser-Fenster (Laptop + Handy) zeigen exakt dieselbe Verzögerung
|
||||
für cam0 bzw. cam1 — synchron auf die Millisekunde. Ändert sich die Latenz
|
||||
von cam0, ändert sie sich auf beiden Clients gleichzeitig.
|
||||
|
||||
→ **Das Problem sitzt in go2rtc/FFmpeg, nicht im Netz oder Browser.**
|
||||
|
||||
### Schritt 4 — Root Cause: FFmpeg-Flags und `exec timeout`
|
||||
|
||||
go2rtc generiert intern folgenden FFmpeg-Befehl:
|
||||
```
|
||||
-readrate_initial_burst 0.001 -re -i /dev/video2
|
||||
-c:v libx264 -g 50 -profile:v high -preset:v superfast -tune:v zerolatency
|
||||
-readrate_initial_burst 0.001 -re -i /dev/videoX
|
||||
-c:v libx264 -g 50 -preset:v superfast -tune:v zerolatency
|
||||
```
|
||||
|
||||
Zwei Probleme identifiziert:
|
||||
**`-re`** = Rate-Emulation für Datei-Wiedergabe — puffert Live-Frames künstlich.
|
||||
**`-g 50`** = Keyframe alle 1,67 s → bis zu 1,67 s Standbild nach Loss/Reconnect.
|
||||
**libx264** = Software-Encoding → CPU-intensiv, skaliert schlecht mit mehreren Clients.
|
||||
|
||||
**Problem A — `-re` (Rate-Emulation für Live-Input):**
|
||||
`-re` = „lies Input im Echtzeit-Takt". Für Datei-Wiedergabe gedacht.
|
||||
Für eine Live-Kamera (die ohnehin Echtzeit-Frames liefert) puffert `-re`
|
||||
Frames künstlich, statt sie sofort durchzureichen. Wenn der Encoder unter
|
||||
Last minimal in Rückstand gerät, baut sich ein Puffer auf → variable Latenz.
|
||||
`-readrate_initial_burst 0.001` macht den Start besonders langsam → erklärt
|
||||
den langsamen Stream-Aufbau.
|
||||
### Phase 3 — Source-Format-Experimente (alle versucht, Ergebnis unbefriedigend)
|
||||
|
||||
**Problem B — `-g 50` (Keyframe-Abstand 1,67 Sekunden bei 30 fps):**
|
||||
H.264 überträgt zwischen Keyframes nur Differenzbilder. Der Browser kann erst
|
||||
ab einem Keyframe decodieren. Nach jedem Paket-Verlust oder Neuverbindung
|
||||
wartet der Browser bis zu 1,67 s auf den nächsten Keyframe → Standbild.
|
||||
Da cam0 und cam1 ihre Keyframe-Takte unabhängig haben, friert mal der eine,
|
||||
mal der andere ein — aber auf allen Clients gleichzeitig (wegen Schritt 3).
|
||||
| Source-Format | Ergebnis | Warum nicht ausreichend |
|
||||
|---------------|----------|------------------------|
|
||||
| `ffmpeg:/dev/video0#video=h264` | ~35% CPU mit 1 Client, Bild funktioniert | `-re` erzeugt variable Latenz |
|
||||
| `ffmpeg:/dev/video0#video=h264#video=mjpeg` | ~95% CPU | Doppeltes Encoding |
|
||||
| `v4l2:/dev/video0#video=h264` | 0% CPU ohne Client (on-demand ✓), **kein Bild** | v4l2: Source unterstützt `#video=h264` nicht |
|
||||
| `ffmpeg:-f v4l2 ...#video=h264` | FFmpeg-Parsing-Fehler: `-f` wird als Dateiname interpretiert | go2rtc splittet den String nicht in Args |
|
||||
| `ffmpeg:device?video=/dev/video0&input_format=mjpeg...#video=h264` | ~103% CPU, Bild funktioniert | Kein `-re` (gut), aber libx264 läuft trotzdem durch |
|
||||
|
||||
**Problem C — `ERR [exec] timeout` für /dev/video2 (cam1):**
|
||||
go2rtc's FFmpeg für cam1 läuft gelegentlich in einen Timeout (Kamera-Init
|
||||
zu langsam, USB-Bandbreitenproblem, Treiberproblem). go2rtc startet den
|
||||
Encoder neu → cam1 friert für mehrere Sekunden ein, während cam0 läuft.
|
||||
### Kern-Erkenntnis (nach Phase 3)
|
||||
|
||||
### Was bisher versucht wurde
|
||||
> **Das Source-Format ist nicht das Problem. libx264 Software-Encoding ist es.**
|
||||
> Egal wie die Frames reinkommen — der Encoder frisst denselben CPU.
|
||||
> Alle Source-Experimente haben daran nichts geändert.
|
||||
|
||||
| Massnahme | Ergebnis |
|
||||
|-----------|----------|
|
||||
| `#video=h264#video=mjpeg` entfernt → nur `#video=h264` | CPU-Last von ~95% auf ~35% reduziert |
|
||||
| `getVideoPlaybackQuality()` als Überlast-Detektor | Fehlalarm (misst Render-Drops, nicht echte Überlast) |
|
||||
| Umstieg auf `getStats()` (inbound-rtp) | Verlässlich, bestätigt: Client ist nicht das Problem |
|
||||
| Aufwärmphase (15s nach `playing`) in Browser-Überwachung | Fehlalarme beim Stream-Aufbau beseitigt |
|
||||
On-Demand-Verhalten ist ein Nebeneffekt: go2rtc startet den Encoder erst bei
|
||||
erstem Client, stoppt bei letztem. Das ist Standard-go2rtc-Verhalten, unabhängig
|
||||
vom Source-Format.
|
||||
|
||||
---
|
||||
|
||||
## Ursachen-Zusammenfassung
|
||||
## Schlussfolgerung: Zwei echte Lösungen
|
||||
|
||||
| Ursache | Symptom | Behebbar ohne go2rtc-Patch? |
|
||||
|---------|---------|----------------------------|
|
||||
| `-re` + `-readrate_initial_burst 0.001` | Variable Latenz, langsamer Aufbau | Ja (anderer Source-Typ) |
|
||||
| `-g 50` (1,67s GOP) | Bis zu 1,67s Standbild | Ja (exec: mit eigenem FFmpeg) |
|
||||
| Software-H.264 × 2 Kameras × n Clients | CPU-Sättigung ab 2 Clients | Ja (Hardware-Encode) |
|
||||
| cam1 FFmpeg timeout | Multi-Sekunden-Freeze cam1 | Teilweise (v4l2: Source) |
|
||||
### Lösung 1 — Hardware-Encoding (Intel QuickSync / VAAPI) ← bevorzugt
|
||||
|
||||
**go2rtc kann diese FFmpeg-Flags nicht per einfacher URL-Syntax konfiguriert werden.**
|
||||
Sie sind hard-coded im `ffmpeg:` Source-Handler von go2rtc 1.9.x.
|
||||
H.264-Encoding auf der Intel-iGPU statt auf der CPU.
|
||||
CPU-Last: ~35% → **~5%**. Latenz unverändert (~130ms WebRTC).
|
||||
|
||||
---
|
||||
|
||||
## Lösungsweg — geordnet nach Aufwand/Wirkung
|
||||
|
||||
### Option A — `v4l2:` Source statt `ffmpeg:` (sofort probieren)
|
||||
go2rtc hat einen nativen v4l2-Treiber, der FFmpeg für den Capture umgeht:
|
||||
```yaml
|
||||
streams:
|
||||
cam0: "v4l2:/dev/video0#video=h264"
|
||||
cam1: "v4l2:/dev/video2#video=h264"
|
||||
```
|
||||
- Kein `-re`, kein `-readrate_initial_burst` → direkter Frame-Durchsatz
|
||||
- Encoding (libx264) bleibt, aber ohne künstliches Puffern
|
||||
- Könnte den `exec timeout` auf cam1 beheben (anderer Kamera-Öffnungspfad)
|
||||
- **Risiko:** v4l2-Source in go2rtc ist weniger getestet als ffmpeg-Source
|
||||
|
||||
### Option B — Hardware-Encoding Intel QuickSync / VAAPI
|
||||
Prüfen ob GPU verfügbar:
|
||||
Voraussetzung prüfen:
|
||||
```bash
|
||||
ls -l /dev/dri # renderD128 vorhanden?
|
||||
ls -la /dev/dri/
|
||||
# renderD128 vorhanden? → Hardware-Encoding möglich
|
||||
```
|
||||
Config:
|
||||
```yaml
|
||||
# go2rtc-Service: devices: + /dev/dri:/dev/dri
|
||||
streams:
|
||||
cam0: "ffmpeg:/dev/video0#video=h264#hardware"
|
||||
cam1: "ffmpeg:/dev/video2#video=h264#hardware"
|
||||
```
|
||||
- Encoding auf GPU → CPU von ~35 % auf ~5 %
|
||||
- go2rtc erzeugt anderen FFmpeg-Befehl (h264_vaapi statt libx264)
|
||||
- Ob `-re` dabei ebenfalls wegfällt: **muss am Gerät verifiziert werden**
|
||||
|
||||
### Option C — Eigener FFmpeg-Befehl via exec: Source
|
||||
Vollständige Kontrolle über alle FFmpeg-Flags:
|
||||
Wenn ja, Umsetzung:
|
||||
```yaml
|
||||
# docker-compose.yaml — go2rtc service:
|
||||
devices:
|
||||
- /dev/video0:/dev/video0
|
||||
- /dev/video2:/dev/video2
|
||||
- /dev/dri:/dev/dri # ← GPU durchreichen
|
||||
|
||||
# go2rtc-Config:
|
||||
streams:
|
||||
cam0: "ffmpeg:device?video=/dev/video0&input_format=mjpeg&video_size=640x480&framerate=30#video=h264#hardware"
|
||||
cam1: "ffmpeg:device?video=/dev/video2&input_format=mjpeg&video_size=640x480&framerate=30#video=h264#hardware"
|
||||
```
|
||||
|
||||
`#hardware` weist go2rtc an, h264_vaapi zu verwenden. go2rtc baut den FFmpeg-Befehl
|
||||
mit VAAPI-Flags — ohne `-re`, mit GPU-Encoding.
|
||||
|
||||
Zu verifizieren nach Aktivierung:
|
||||
1. CPU fällt auf <10%?
|
||||
2. Latenz stabil <200ms?
|
||||
3. `go2rtc`-Log zeigt `h264_vaapi` statt `libx264`?
|
||||
|
||||
### Lösung 2 — MJPEG (Fallback, sofort umsetzbar)
|
||||
|
||||
Kein Encoding, kein GOP, keine CPU-Last. War nachweislich stabil und flüssig.
|
||||
Latenz ~200ms (70ms mehr als WebRTC — für Roboter-Überwachung vertretbar).
|
||||
|
||||
```yaml
|
||||
streams:
|
||||
cam0:
|
||||
- "ffmpeg:-f v4l2 -input_format mjpeg -video_size 640x480 -framerate 30
|
||||
-fflags nobuffer -flags low_delay
|
||||
-i /dev/video0
|
||||
-c:v libx264 -preset ultrafast -tune zerolatency -g 15 -bf 0
|
||||
#video=h264"
|
||||
cam0: "ffmpeg:device?video=/dev/video0&input_format=mjpeg&video_size=640x480&framerate=30#video=mjpeg"
|
||||
cam1: "ffmpeg:device?video=/dev/video2&input_format=mjpeg&video_size=640x480&framerate=30#video=mjpeg"
|
||||
```
|
||||
- Kein `-re` (nicht angegeben)
|
||||
- `-g 15` = Keyframe alle 0,5 s → max 0,5 s Freeze
|
||||
- `-fflags nobuffer -flags low_delay` = minimaler Input-Buffer
|
||||
- **Problem:** go2rtc's `ffmpeg:` Source-Handler mit Custom-Args ist Version-abhängig;
|
||||
korrekte Syntax muss verifiziert werden
|
||||
|
||||
### Option D — Separater MediaMTX-Container
|
||||
MediaMTX (rtsp-simple-server) als Zwischenstufe:
|
||||
Im Browser-Viewer `MODE` anpassen:
|
||||
```javascript
|
||||
const MODE = 'mjpeg'; // statt 'webrtc,mse,mjpeg'
|
||||
```
|
||||
v4l2 → FFmpeg (eigene Flags, g=15, kein -re) → RTSP (MediaMTX) → go2rtc → WebRTC
|
||||
```
|
||||
- Volle FFmpeg-Kontrolle
|
||||
- go2rtc liest einfach `rtsp://mediamtx:8554/cam0`
|
||||
- Zusätzlicher Container, aber sauber und wartbar
|
||||
|
||||
### Option E — Fallback: MJPEG
|
||||
```yaml
|
||||
streams:
|
||||
cam0: "ffmpeg:/dev/video0#video=mjpeg"
|
||||
```
|
||||
- Kein H.264-Encode, kein GOP, keine `-re`-Problematik
|
||||
- ~200 ms Latenz (statt 130 ms) — bei 1–3 Usern und Roboter-Überwachung ausreichend
|
||||
- War nachweislich stabil und flüssig
|
||||
CPU erwartet: **<5%**. Kein `-g 50`, keine Freezes, kein Encoding-Jitter.
|
||||
|
||||
---
|
||||
|
||||
## Empfohlene Reihenfolge
|
||||
## Ergebnis aller Versuche — Entscheid
|
||||
|
||||
### Hardware-Encoding: gescheitert (go2rtc-Limitation)
|
||||
|
||||
`renderD128` ist vorhanden (`ls -la /dev/dri/` bestätigt). go2rtc's `#hardware`
|
||||
verwendet `-hwaccel vaapi -hwaccel_output_format vaapi` auf Input-Seite. Das setzt
|
||||
voraus, dass der **Decoder** VAAPI nutzt. MJPEG von v4l2 wird aber per Software
|
||||
dekodiert — `hwupload` findet keine VAAPI-Device-Referenz → Filterchain-Fehler.
|
||||
|
||||
```
|
||||
1. Option A (v4l2: Source) → 5 min, kein Aufwand, könnte alles lösen
|
||||
2. Option B (Hardware-Encode) → 15 min, braucht /dev/dri-Check
|
||||
3. Option C (custom FFmpeg) → 30 min, volle Kontrolle
|
||||
4. Option D (MediaMTX) → 60 min, sauberste Architektur
|
||||
5. Option E (MJPEG) → 5 min, sicherer Hafen
|
||||
[hwupload] A hardware device reference is required to upload frames to.
|
||||
[AVFilterGraph] Error initializing filters
|
||||
```
|
||||
|
||||
go2rtc's `#hardware` ist für Re-Encoding von RTSP-H.264-Streams gebaut,
|
||||
**nicht** für MJPEG-Kamera-Input. Ohne eigenen FFmpeg-Befehl (den go2rtc nicht
|
||||
erlaubt) ist Hardware-Encoding für diesen Use-Case nicht erreichbar.
|
||||
|
||||
### Entscheid: MJPEG-Passthrough ✓ (umgesetzt)
|
||||
|
||||
```yaml
|
||||
cam0: "ffmpeg:device?video=/dev/video0&input_format=mjpeg&video_size=640x480&framerate=30#video=mjpeg"
|
||||
cam1: "ffmpeg:device?video=/dev/video2&input_format=mjpeg&video_size=640x480&framerate=30#video=mjpeg"
|
||||
```
|
||||
|
||||
Kamera liefert MJPEG nativ → go2rtc reicht es 1:1 durch → kein Encoding → CPU <5%.
|
||||
|
||||
| | H.264 Software | H.264 Hardware | **MJPEG Passthrough** |
|
||||
|-|---------------|----------------|----------------------|
|
||||
| CPU | ~100% | gescheitert | **<5%** |
|
||||
| Latenz | ~130ms | — | **~200ms** |
|
||||
| Freezes | gelegentlich | — | **keine** |
|
||||
| Stabilität | mittel | — | **hoch** |
|
||||
|
||||
70ms mehr Latenz ist für Roboter-Überwachung vertretbar.
|
||||
Snapshots haben native JPEG-Qualität (kein H.264-Artefakte).
|
||||
|
||||
### Falls doch noch H.264 gewünscht (mit korrektem VAAPI)
|
||||
|
||||
Erfordert MediaMTX als Zwischenstufe:
|
||||
```
|
||||
v4l2 → FFmpeg (vaapi_device + eigene Flags) → RTSP (MediaMTX) → go2rtc WebRTC
|
||||
```
|
||||
FFmpeg-Befehl der funktionieren würde:
|
||||
```bash
|
||||
ffmpeg -vaapi_device /dev/dri/renderD128 \
|
||||
-f v4l2 -input_format mjpeg -video_size 640x480 -framerate 30 -i /dev/video0 \
|
||||
-vf "format=nv12,hwupload" -c:v h264_vaapi -g 15 -bf 0 \
|
||||
-f rtsp rtsp://mediamtx:8554/cam0
|
||||
```
|
||||
Aufwand: ~2h (zusätzlicher Container, RTSP-Verkabelung). Lohnt sich erst wenn
|
||||
200ms Latenz nachweislich ein Problem für den Anwendungsfall ist.
|
||||
|
||||
---
|
||||
|
||||
## Hi-Res-Snapshots — Analyse (Live-Video + Foto alle ~10 s)
|
||||
## Hi-Res-Snapshots
|
||||
|
||||
**Grundprinzip:** Snapshot-Auflösung = Stream-Auflösung (USB-Kamera kann nur
|
||||
in einer Auflösung gleichzeitig geöffnet sein). Für Hi-Res-Fotos muss der
|
||||
Stream selbst hochauflösend laufen, Browser skaliert fürs Display herunter.
|
||||
Snapshot-Auflösung = Stream-Auflösung (USB-Kamera kann nur in einer Auflösung
|
||||
gleichzeitig geöffnet sein).
|
||||
|
||||
### Weg A — MJPEG hochauflösend (Passthrough, Option E oben)
|
||||
- Kamera liefert MJPEG nativ → go2rtc reicht 1:1 durch, kein Encode
|
||||
- Snapshot: `/api/frame.jpeg` = voller Frame, native JPEG-Qualität, gratis
|
||||
- CPU ~5 %, keine Freezes
|
||||
- Empfohlen wenn Hardware-Encoding nicht verfügbar
|
||||
Bei **Lösung 1** (Hardware H.264): Stream hochauflösend konfigurieren, Browser
|
||||
skaliert herunter. `/api/frame.jpeg` liefert H.264-Frame (leicht verlustbehaftet).
|
||||
Beste Qualität: zusätzlich `#video=mjpeg` für Snapshot-Track (wenn GPU übrig hat).
|
||||
|
||||
### Weg B — H.264 Hardware-Encode + MJPEG-Passthrough (Option B oben)
|
||||
```yaml
|
||||
cam0: "ffmpeg:/dev/video0#video=h264#hardware#video=mjpeg"
|
||||
```
|
||||
- Live: H.264 per GPU (~130 ms, niedrige Bandbreite)
|
||||
- Snapshot: MJPEG-Passthrough (native Qualität, gratis)
|
||||
- Zu verifizieren: welchen Track nimmt `/api/frame.jpeg` — H.264 oder MJPEG?
|
||||
|
||||
### Snapshot-Takt
|
||||
Der 10-s-Takt erzeugt keine Dauerlast: pro Foto wird ein Frame aus dem
|
||||
laufenden Stream abgegriffen. Trigger: Homing-Projekt ruft
|
||||
`GET /api/snapshot/cam0` alle 10 s ab (aktuell so implementiert).
|
||||
Bei **Lösung 2** (MJPEG): `/api/frame.jpeg` = natives Kamera-JPEG, volle Qualität, gratis.
|
||||
|
||||
@@ -25,20 +25,13 @@ configs:
|
||||
# Komplette go2rtc-Config eingebettet – keine separate Datei nötig.
|
||||
content: |
|
||||
streams:
|
||||
# Option C — ffmpeg: mit expliziten Input-Flags, OHNE -re und OHNE -readrate_initial_burst.
|
||||
# go2rtc ist on-demand: startet FFmpeg erst wenn ein Client verbindet (bestätigt: 0% CPU ohne Client).
|
||||
# -input_format mjpeg → Kamera-natives MJPEG, kein Pixel-Decode nötig
|
||||
# -fflags nobuffer → kein Input-Puffer
|
||||
# -flags low_delay → minimaler Decoder-Delay
|
||||
# -probesize 32 → keine lange Format-Analyse beim Start
|
||||
# -analyzeduration 0 → sofortiger Start
|
||||
# go2rtc übernimmt H.264-Encoding (-g 50 bleibt, aber ohne -re-Stau).
|
||||
cam0: "ffmpeg:-f v4l2 -input_format mjpeg -video_size 640x480 -framerate 30 -fflags nobuffer -flags low_delay -probesize 32 -analyzeduration 0 -i /dev/video0#video=h264"
|
||||
cam1: "ffmpeg:-f v4l2 -input_format mjpeg -video_size 640x480 -framerate 30 -fflags nobuffer -flags low_delay -probesize 32 -analyzeduration 0 -i /dev/video2#video=h264"
|
||||
#
|
||||
# Option B – Hardware-Encoding (nächster Schritt falls CPU noch zu hoch):
|
||||
# cam0: "ffmpeg:-f v4l2 -input_format mjpeg -video_size 640x480 -framerate 30 -fflags nobuffer -flags low_delay -i /dev/video0#video=h264#hardware"
|
||||
# cam1: "ffmpeg:-f v4l2 -input_format mjpeg -video_size 640x480 -framerate 30 -fflags nobuffer -flags low_delay -i /dev/video2#video=h264#hardware"
|
||||
# MJPEG-Passthrough: Kamera liefert MJPEG nativ → go2rtc reicht es 1:1 durch.
|
||||
# Kein Encoding, kein libx264, kein VAAPI → CPU <5%, keine Freezes.
|
||||
# Latenz ~200ms (vs. 130ms bei H.264) — für Roboter-Überwachung ausreichend.
|
||||
# Hinweis: go2rtc's #hardware funktioniert NICHT mit MJPEG-Kamera-Input
|
||||
# (hwupload benötigt VAAPI-Decoder auf Input-Seite, MJPEG läuft Software).
|
||||
cam0: "ffmpeg:device?video=/dev/video0&input_format=mjpeg&video_size=640x480&framerate=30#video=mjpeg"
|
||||
cam1: "ffmpeg:device?video=/dev/video2&input_format=mjpeg&video_size=640x480&framerate=30#video=mjpeg"
|
||||
webrtc:
|
||||
listen: ":8555"
|
||||
candidates:
|
||||
@@ -54,10 +47,7 @@ configs:
|
||||
origin: "*"
|
||||
log:
|
||||
level: info
|
||||
# TODO (on-demand Encoding): go2rtc hält den Encoder auch ohne Clients am Laufen.
|
||||
# Das verbraucht unnötig ~35% CPU wenn niemand zuschaut.
|
||||
# Lösung: v4l2:/dev/video0 ohne #video=h264 → go2rtc öffnet Kamera nur bei Bedarf?
|
||||
# Oder: mediamtx als Zwischenstufe (hat explizites on-demand). Prüfen.
|
||||
# On-demand bestätigt: go2rtc startet Encoder erst bei erstem Client (0% CPU ohne Client).
|
||||
|
||||
services:
|
||||
|
||||
@@ -70,8 +60,11 @@ services:
|
||||
devices:
|
||||
- /dev/video0:/dev/video0
|
||||
- /dev/video2:/dev/video2
|
||||
# /dev/dri nicht mehr nötig: MJPEG-Passthrough braucht keine GPU
|
||||
group_add:
|
||||
- video
|
||||
# render-Gruppe NICHT hier setzen — existiert im Container-Image nicht → 500-Fehler.
|
||||
# /dev/dri-Zugriff funktioniert via devices: + Container läuft als root.
|
||||
configs:
|
||||
- source: go2rtc_yaml
|
||||
target: /config/go2rtc.yaml
|
||||
|
||||
Reference in New Issue
Block a user