Fresh installs now show the overlay over the live picture in the web UI without any server-side overlay processing. Previously the overlay defaulted to off entirely. The change is just to loadState()'s default values; both fields are still read from the state file when present, so existing users who have explicitly toggled either setting keep their preference. Users upgrading from before overlay_baked existed get the new HTML default (was implicitly baked before). Behavior with the new defaults on a fresh install: - Master overlay: on - Overlay type: HTML (baked off) - runOverlay() drops frames without decoding (no CPU overhead) - /stream/overlay and /snapshot/overlay return 503 (HTML mode) - RTSP overlay process does not start - Web UI shows stats overlaid via CSS on top of the raw stream Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6.7 KiB
OctoCam
Live webcam streaming for a 3D printer with OctoPrint stats burned into the overlay feed. Built with Go + MediaMTX. Runs on Raspberry Pi, Rock64, and any arm64/armv7 SBC.
Pages
| URL | Description |
|---|---|
http://<host>:8080/ |
Both feeds side by side with stats and RTSP toggles |
http://<host>:8080/raw |
Raw feed — bare full-screen (no UI chrome) |
http://<host>:8080/overlay |
Overlay feed — bare full-screen (no UI chrome) |
Streams
| URL | Description |
|---|---|
http://<host>:8080/stream/raw |
Raw MJPEG HTTP (for direct embedding) |
http://<host>:8080/stream/overlay |
Overlay MJPEG HTTP (for direct embedding) |
http://<host>:8080/snapshot/raw |
Single JPEG snapshot of the raw feed |
http://<host>:8080/snapshot/overlay |
Single JPEG snapshot of the overlay feed |
rtsp://<host>:8554/raw |
Raw RTSP — use as OctoPrint webcam URL or open in VLC |
rtsp://<host>:8554/overlay |
Overlay RTSP — OctoPrint webcam URL with stats |
RTSP feeds can be toggled on/off at runtime from the web UI without restarting the service.
The raw HTTP stream and snapshot (/stream/raw, /snapshot/raw, and the mjpg_streamer-compatible /webcam/?action=stream and /webcam/?action=snapshot) are always available, regardless of any runtime toggle. They never carry the overlay. Point OctoPrint's Classic Webcam plugin at these URLs for reliable live feeds and snapshot capture.
The overlay feed is a separate master toggle (rendering, MJPEG, RTSP). It defaults to on in HTML mode, so a fresh install shows the stats over the live picture in the web UI without doing any server-side JPEG decode/draw/encode. The RTSP overlay sub-toggle is preserved across master toggles but the ffmpeg process only runs when the master is on and the overlay type is baked.
Overlay type can be switched at runtime between two modes:
- HTML (default): the overlay is drawn client-side over the raw stream. No JPEG decode/draw/encode on the server. Web-only —
/stream/overlayand/snapshot/overlayreturn 503 and the RTSP overlay process is stopped. - Baked: the overlay is rendered server-side and burned into the JPEG frames. Required for OctoPrint, VLC, or any consumer that expects the stats inside the video stream. Higher CPU cost.
All toggles — master overlay, overlay type, and both RTSP feed states — persist in the state file (/var/lib/octocam/feeds.json by default) and survive reboots.
Architecture
USB webcam ──→ octocam (Go)
│ ← OctoPrint API (temps, state, progress)
│
├─ /stream/raw MJPEG HTTP ──→ browser
├─ /stream/overlay MJPEG HTTP ──→ browser
├─ /, /raw, /overlay web pages
│
├─ ffmpeg raw -c:v copy (passthrough) ──→ MediaMTX /raw
└─ ffmpeg overlay H264 ultrafast @ 5fps ──→ MediaMTX /overlay
│
RTSP :8554 ──→ VLC / OctoPrint
Browser streams are served directly as MJPEG HTTP — no WebRTC, no HLS, no extra encoding. The RTSP feeds via MediaMTX are for external tools and are optional (toggleable).
Quick Install
Build the binary on your dev machine first, then copy the repo to the target board and run the installer.
On your dev machine:
git clone https://git.enclaveis.com/Enclave-Information-Systems/octocam
cd octocam
make build-pi # arm64 (Pi 4/5, Rock64, etc.)
# or: make build-pi32 # armv7 (32-bit OS)
On the board:
cp .env.example /etc/octocam.env
# Edit /etc/octocam.env — set OCTOPRINT_API_KEY and OCTOCAM_DEVICE
sudo bash deploy/install.sh
sudo systemctl start octocam
Open http://<board-ip>:8080/ in a browser.
Configuration
All settings are environment variables read from /etc/octocam.env (service) or .env (local dev). See .env.example for the full list. The only required variable is OCTOPRINT_API_KEY — get it from OctoPrint → Settings → API.
Key settings:
| Variable | Default | Description |
|---|---|---|
OCTOCAM_DEVICE |
/dev/video0 |
V4L2 camera device |
OCTOCAM_WIDTH / OCTOCAM_HEIGHT |
1280 / 720 |
Capture resolution |
OCTOCAM_FPS |
15 |
Camera framerate |
OCTOCAM_OVERLAY_RTSP_FPS |
5 |
RTSP overlay framerate (lower = less CPU) |
OCTOCAM_FFMPEG_HW |
auto |
Encoder: auto, h264_v4l2m2m, h264_rkmpp, libx264 |
OCTOCAM_BASE_PATH |
(empty) | URL prefix for hosting at a sub-path, e.g. /octocam |
OCTOCAM_STATE_FILE |
/var/lib/octocam/feeds.json |
Persists RTSP feed state across reboots |
OCTOPRINT_URL |
http://localhost:5000 |
OctoPrint base URL |
OCTOPRINT_API_KEY |
— | Required |
RTSP feeds default to off on first run. Enable them from the web UI — the state is saved immediately and survives reboots.
API
| Method | Path | Description |
|---|---|---|
GET |
/api/stats |
OctoPrint snapshot (temps, progress, state) |
GET |
/api/feeds |
RTSP feed states {"raw":{"enabled":true,"running":true},...} |
POST |
/api/feeds/raw |
Toggle raw RTSP — body {"enabled": false} |
POST |
/api/feeds/overlay |
Toggle overlay RTSP — body {"enabled": true} |
GET |
/api/overlay |
Overlay state {"enabled": false, "type": "baked"} |
POST |
/api/overlay |
Set overlay state — body {"enabled": true} and/or {"type": "html"} |
GET |
/snapshot/raw |
Single JPEG frame from the raw feed |
GET |
/snapshot/overlay |
Single JPEG frame from the overlay feed (503 when master overlay off) |
GET |
/healthz |
Health check — 200 ok or 503 degraded |
Overlay
The overlay stream burns four regions onto each frame:
- Top-left: Printer state pill (green Printing / yellow Paused / red Error) + filename
- Top-right:
H: actual/target °CandB: actual/target °C - Bottom: Progress bar +
% elapsed H:MM:SS ETA H:MM:SS
When OctoPrint is unreachable the overlay shows a single red "OctoPrint unreachable" badge; the camera stream continues uninterrupted.
Development
# Build for the current machine
make build
# Cross-compile for arm64 boards
make build-pi
# Run locally (needs a USB webcam and MediaMTX running on localhost)
cp .env.example .env
# Edit .env — set OCTOPRINT_API_KEY
OCTOPRINT_API_KEY=xxx ./octocam
Run MediaMTX locally for dev:
# Linux amd64
curl -fsSL https://github.com/bluenviron/mediamtx/releases/latest/download/mediamtx_linux_amd64.tar.gz | tar xz
./mediamtx deploy/mediamtx.yml