Files
appRobotWebcam/docker-compose.yaml
2026-06-08 20:53:24 +02:00

141 lines
8.6 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: approbotwebcam
# ════════════════════════════════════════════════════════════════════════════
# AppRobotWebcam Node-MJPEG-Schalter
# ════════════════════════════════════════════════════════════════════════════
#
# Node besitzt jede Kamera direkt (eine CameraSwitch-Instanz pro /dev/videoN).
# Live: FFmpeg → MJPEG multipart → Browser <img>. Latenz: ~139 ms.
# HD-Grab: Live-FFmpeg stoppen (close-Event = FD frei) → hires-FFmpeg →
# JPEG an Client → Live zurück. Auflösungen in cameras.json konfiguriert.
#
# Kameras (aktuell, by-id = stabil über Reboots):
# cam0 C270 /dev/video0 Live 640×480, Hires 1280×960
# cam1 C270 /dev/video2 Live 640×480, Hires 1280×960
# cam2 C920 /dev/video4 Live 640×480, Hires 1920×1080
#
# Portainer: Stack → Web editor → dieses YAML → Deploy.
# APP_PATH = /absoluter/pfad/zum/appRobotWebcam
#
# Netz: hängt am externen Bridge-Netz "approbot_default" → vom HTTPS-Proxy im
# selben Netz erreichbar als http://AppRobotWebcam:8444 (oder webcam:8444).
# Firewall: TCP 8444 am Host nur für direkten LAN-Zugriff (ports:-Mapping). Läuft
# alles über den Proxy → ports:-Zeile raus, dann ist am Host nichts offen.
#
# Zugriff:
# Viewer: http://<host>:8444/
# Live-Stream: http://<host>:8444/api/stream/cam0
# Snapshot: http://<host>:8444/api/snapshot/cam0
# HD-Snapshot: http://<host>:8444/api/snapshot/cam0/hires
# Kamera-Liste: http://<host>:8444/api/cameras
# Status: http://<host>:8444/health
# ════════════════════════════════════════════════════════════════════════════
services:
webcam:
build:
context: /tmp
# Bewusst minimal & identisch zum bekannten, funktionierenden Stand: nur ffmpeg.
# Der GPU-VA-Treiber wird NICHT hier gebaut (ein fehlschlagender apt-Build im
# dockerfile_inline lässt Portainer mit 500 abbrechen → es bleibt beim alten
# Stack). Stattdessen Treiber-Install beim Start, siehe 'command' weiter unten.
dockerfile_inline: |
FROM node:lts-bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends ffmpeg \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /usr/src/app
EXPOSE 8444
image: approbotwebcam:latest
container_name: AppRobotWebcam
restart: unless-stopped
# Hängt am externen Netz approbot_default (statt host-Mode) → der HTTPS-Proxy im
# selben Netz erreicht den Container per Name (http://AppRobotWebcam:8444).
networks:
- approbot_default
# 8444 am Host veröffentlicht → direkter LAN-Zugriff (http://<host>:8444) bleibt.
# Wenn ALLES über den Proxy läuft, diesen ports-Block entfernen → proxy-only.
ports:
- "8444:8444"
# GPU-VA-Treiber beim Start installieren (kein Image-Rebuild → kein Build-500).
# Schlägt der Treiber-Install fehl (z.B. kein Netz), startet die App trotzdem
# dann läuft MJPEG normal weiter, nur H.264 ist bis zum Fix nicht verfügbar.
# Intel UHD 630 → i965-va-driver. AMD-Box: 'mesa-va-drivers' ergänzen.
command: >
sh -c "(apt-get update && apt-get install -y --no-install-recommends i965-va-driver libva-drm2 vainfo) || echo 'WARN: VA-Treiber-Install fehlgeschlagen H.264 evtl. nicht verfuegbar';
npm install --omit=dev && node server.js"
volumes:
- ${APP_PATH:-.}:/usr/src/app
devices:
# by-id (Host) → /dev/videoN (Container) stabil über Reboots und USB-Re-Plugs.
# Rechte Seite = Pfad den cameras.json + FFmpeg im Container sehen.
- /dev/v4l/by-id/usb-046d_0825_3BB3FE20-video-index0:/dev/video0 # cam0 C270 (046d:0825)
- /dev/v4l/by-id/usb-046d_081b_342D4F40-video-index0:/dev/video2 # cam1 C270 (046d:081b)
- /dev/v4l/by-id/usb-046d_HD_Pro_Webcam_C920_9C5591DF-video-index0:/dev/video4 # cam2 C920
# GPU-Renderknoten für H.264-Encoding (VAAPI Intel/AMD). Nur nötig, wenn eine
# Kamera encode='h264' nutzt. Auf der Intel-Box bestätigt: /dev/dri/renderD128.
- /dev/dri:/dev/dri
group_add:
- video
# render-Gruppe entfernt existiert auf Synology DSM nicht → Docker API 500.
# Root hat ohnehin Zugriff auf /dev/dri/renderD128.
environment:
- NODE_ENV=production
- PORT=8444
- LIBVA_DRIVER_NAME=i965 # Coffee Lake / UHD 630 → i965 direkt (überspringt iHD-Fehlversuch).
# AMD-Box: auf 'radeonsi' ändern (und mesa-va-drivers installieren).
# Kamera-Konfiguration (Gerät, Name, Auflösung) → cameras.json im APP_PATH
# Globale Fallback-Werte (gelten wenn cameras.json keinen Wert hat):
# - LIVE_SIZE=640x480
# - LIVE_FPS=30
# - HIRES_SIZE=1280x960
# - HIRES_FPS=15
# - ENCODE_MODE=copybsf # copybsf = Bitstream-Copy, niedrige CPU (Default)
# # mjpeg = Re-Encode (~50%, Fallback falls copybsf zickt)
# # h264 = GPU-H.264 → MSE (Bandbreite sparen, braucht GPU)
# - ON_DEMAND=true # Live nur bei Zuschauern (Default); 'false' = dauerhaft an
# - IDLE_GRACE_MS=15000 # Karenz nach letztem Zuschauer vor dem Stop
#
# ── H.264-Hardware-Encoding (nur relevant für encode='h264') ──────────────
# - GPU=intel # intel|amd → VAAPI (gemeinsamer Pfad) · none → libx264 (CPU-Test)
# # → HIER die Maschine wählen: 'intel' (UHD 630) oder 'amd' (680M)
# - HWENC=vaapi # vaapi|qsv|libx264 Encoder erzwingen (überschreibt GPU)
# - HWENC_DEVICE=/dev/dri/renderD128 # VAAPI/QSV-Renderknoten
# - H264_BITRATE=3M # Zielbitrate
# - H264_GOP= # Keyframe-Abstand (Default ~2×fps); kleiner = schnellerer Einstieg, mehr Bitrate
# - H264_PROFILE=main # constrained_baseline|main|high (muss zum Treiber passen)
# - H264_FRAG_MS=200 # fMP4-Fragmentlänge in ms
# - H264_JPEG_FPS=2 # Bildrate des MJPEG-Nebenausgangs (für /api/snapshot)
# - H264_MSE_CODEC= # MSE-Codec-String überschreiben, falls der Browser meckert (z.B. avc1.640020)
# ── Netzwerk ────────────────────────────────────────────────────────────────────
# Externes, bereits existierendes Bridge-Netz (vom Stack "approbot"). Wird hier nur
# referenziert, nicht erstellt. Prüfen: docker network inspect approbot_default
networks:
approbot_default:
external: true
name: approbot_default
# ── Hinweise ────────────────────────────────────────────────────────────────────
# • Neue oder geänderte Kamera: cameras.json anpassen + Redeploy (kein Code-Änderung).
# by-id-Namen ermitteln: ls -la /dev/v4l/by-id/
# Neues Device hier eintragen (by-id → /dev/videoN), dann cameras.json-Eintrag.
#
# • Bleibt eine Kamera schwarz oder liefert falsche Auflösung?
# Direkt auf dem Host testen (ohne Docker, beweist was die Kamera real kann):
# node tools/hires-probe.js /dev/video4 1920x1080 copybsf
# Alternativ manuell:
# v4l2-ctl --list-formats-ext -d /dev/video4 # MJPG-Auflösungen anzeigen
# Nur MJPEG-native Auflösungen in cameras.json verwenden (YUYV = Software-Encode = ~50% CPU).
#
# • HD-Grab liefert schlechte Qualität?
# Standard ist copybsf (Kamera-JPEG pur, keine zweite Kompression).
# "hiresEncode": "mjpeg" in cameras.json nur als Fallback, erzeugt Re-Encode-Artefakte.
#
# • Code-Stand im Container prüfen:
# docker exec AppRobotWebcam grep -n "Grab (minWidth" src/cameraSwitch.js
# Zeigt die neue Log-Zeile → aktueller Code läuft. "1280-Grab" → staler Code.
#
# • Compose v2 ist Pflicht (dockerfile_inline). Bei Portainer-Warnung: Docker-Engine updaten.
# ────────────────────────────────────────────────────────────────────────────────