From 831dbc242bc0a0fad708f5a01616aaa4d188dc5b Mon Sep 17 00:00:00 2001 From: chk <79915315+ChKendel@users.noreply.github.com> Date: Thu, 4 Jun 2026 06:41:15 +0200 Subject: [PATCH] =?UTF-8?q?Claude:=20miese=20Aufl=C3=B6sung?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/02_HardwareEncoding.md | 109 +++++++++++++++ doc/04_Delay_roadmap.md | 275 +++++++++++++++++-------------------- docker-compose.yaml | 29 ++-- 3 files changed, 248 insertions(+), 165 deletions(-) create mode 100644 doc/02_HardwareEncoding.md diff --git a/doc/02_HardwareEncoding.md b/doc/02_HardwareEncoding.md new file mode 100644 index 0000000..21f6a79 --- /dev/null +++ b/doc/02_HardwareEncoding.md @@ -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`) diff --git a/doc/04_Delay_roadmap.md b/doc/04_Delay_roadmap.md index f9aac22..154c5d6 100644 --- a/doc/04_Delay_roadmap.md +++ b/doc/04_Delay_roadmap.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. diff --git a/docker-compose.yaml b/docker-compose.yaml index 3c01440..fdf239a 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -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