# Stream-Komprimierung (MJPEG → H.264) — Abarbeitungsliste > **Status (2026-06-16):** Der H.264-Pfad ist **im Code vollständig vorhanden und > unit-getestet**, aber **noch nie auf dem Host scharf geschaltet oder gemessen**. > Diese Datei ist die ausführbare ToDo-Liste, um ihn in Betrieb zu nehmen — destilliert > aus [14_ReRender_roadmap.md](14_ReRender_roadmap.md) (Hintergrund/Entwurf), > [02_HardwareEncoding.md](02_HardwareEncoding.md), [03_Protocoll_roadmap.md](03_Protocoll_roadmap.md) > und [04_Delay_roadmap.md](04_Delay_roadmap.md). > > **Es ist also kein „von Null bauen".** Die offene Arbeit ist: *scharf schalten → messen → > tunen → ausrollen* — und zwar **auf dem Host gemessen, nicht vorhergesagt** > (Memory-Regel; alle Zahlen unten ohne Messung sind ausdrücklich **Hypothesen**). --- ## Ausgangslage in einem Satz Der Live-Stream geht heute als **MJPEG** raus (jedes Frame ein vollständiges JPEG). Das ist zwar pro Frame komprimiert, aber ohne Inter-Frame-Kompression → hohe Bitrate, und der Client muss jedes Frame einzeln dekodieren und in ein `` schieben. Bei mehreren Kameras bringt das schwache Laptops an die Grenze. Mehr Kameras kommen → das Problem wächst. ## Warum H.264 dem Laptop hilft (Motivation + eine Korrektur) „Unkomprimiert" trifft es nicht ganz — MJPEG **ist** komprimiert, nur eben **intra-frame**. Der Gewinn von H.264 ist trotzdem real und doppelt: 1. **Inter-Frame-Kompression** (nur Bildänderungen übertragen) → deutlich weniger Bitrate (Hypothese: ~2–5 MBit/s statt MJPEG-Bitrate; vor dem Umbau messen, siehe ToDo 0). 2. **Hardware-Decode im Browser** — H.264 dekodiert der Client in der GPU; MJPEG dekodiert er pro Frame auf der CPU/im Main-Thread und tauscht das ``. Genau **das** ist die Last, die mehrere Streams auf dem Laptop erzeugen. → H.264 entlastet primär den Client. > ⚠️ **Realität prüfen, nicht annehmen:** Alle Kameras laufen aktuell auf `liveSize` > **320×240** ([../cameras.json](../cameras.json)). `1920x1080` dort ist die `hiresSize` > (Einzelbild beim HD-Knopf), **kein** Dauerstream. Bei 320×240 ist die MJPEG-Bitrate schon > klein → der Bandbreiten-Gewinn könnte gering sein, der **Client-Decode-Gewinn** aber > trotzdem zählen. Das entscheidet ToDo 0. --- ## Was bereits im Code steckt (Datei-Pointer) | Baustein | Datei | Zustand | |---|---|---| | Encoder-Wahl (VAAPI/QSV/libx264) + MSE-Codec-String + FFmpeg-Args | [../src/hwencode.js](../src/hwencode.js) | ✅ + Unit-Test [../test/hwencode.test.js](../test/hwencode.test.js) | | fMP4-Box-Parser (Init-Segment + Fragmente) | [../src/fmp4Parser.js](../src/fmp4Parser.js) | ✅ + Unit-Test [../test/fmp4Parser.test.js](../test/fmp4Parser.test.js) | | `encode='h264'`-Zweig: Init-Cache, Fan-out, MJPEG-Nebenausgang (fd 3) für Snapshots | [../src/cameraSwitch.js](../src/cameraSwitch.js) | ✅ | | `video/mp4`-Route (Init-first Fan-out), `encode`/`mseCodec` in `/api/snapshot`+`/api/cameras` | [../src/snapshotService.js](../src/snapshotService.js) | ✅ | | MSE-`