| author | Clayton Gentry <clayton@podstock.io> | 2026-08-14 03:34:15 -0400 |
|---|---|---|
| committer | Clayton Gentry <clayton@podstock.io> | 2026-08-14 13:22:37 -0400 |
| commit | 3903e4d06351637151889b9ee64844e7f54d7b44 (patch) | |
| tree | f9ee1b10cbf861b2a61e3e198907e6e299db8517 | |
| parent | 007f8616fa067800ecc04406ff8385d48762450d (diff) | |
| download | cribd-3903e4d063.tar.gz zip | |
Add Reolink stream adapter
Keep direct RTSP streams unchanged and add a Reolink path that copies H.264 while converting AAC audio to Opus inside MediaMTX. Pass camera URLs through the inherited container environment and document the boundary between stream and event adapters.
Diffstat
| .env.example | +1 | -0 |
| CHANGELOG.md | +1 | -0 |
| README.md | +22 | -15 |
| adapters/reolink/stream (new) | +24 | -0 |
| bin/cribd | +42 | -6 |
| changelog/2026-08-13-camera-adapters.md (new) | +9 | -0 |
6 files changed, 99 insertions(+), 21 deletions(-)
diff --git a/.env.example b/.env.example @@ -1,1 +1,2 @@ +CRIBD_ADAPTER=direct CRIBD_RTSP_URL=rtsp://user:pass@camera/stream diff --git a/CHANGELOG.md b/CHANGELOG.md @@ -2,6 +2,7 @@ ## 2026 +- **AUG.13** — [Camera Adapters](changelog/2026-08-13-camera-adapters.md) - **AUG.13** — [Stream Status](changelog/2026-08-13-stream-status.md) - **AUG.13** — [Local Network Viewing](changelog/2026-08-13-local-network-viewing.md) - **AUG.13** — [RTSP to WebRTC](changelog/2026-08-13-rtsp-to-webrtc.md) diff --git a/README.md b/README.md @@ -1,6 +1,6 @@ # cribd -`cribd` turns one RTSP camera stream into browser-friendly WebRTC for a local, private baby monitor. [MediaMTX](https://github.com/bluenviron/mediamtx) handles the media path; optional hardware adapters can provide camera-specific events without putting vendor logic in the server. +`cribd` turns one camera stream into browser-friendly WebRTC for a local, private baby monitor. Camera adapters normalize media for [MediaMTX](https://github.com/bluenviron/mediamtx); future event adapters can add hardware-specific events without putting vendor logic in the server. > [!WARNING] > This project is not a medical device or a substitute for safe-sleep practices, direct supervision, or any medically indicated monitor. @@ -7,7 +7,7 @@ ## Status -The current prototype runs on an Apple silicon Mac and serves one stream through a status-aware WebRTC viewer. It is loopback-only by default and can also serve devices on the same local network. Event adapters, remote access, persistence, and Raspberry Pi deployment come later. +The current prototype runs on an Apple silicon Mac and serves one stream through a status-aware WebRTC viewer. Direct and Reolink stream adapters are available. Viewing is loopback-only by default and can be enabled for devices on the same local network. Event adapters, remote access, persistence, and Raspberry Pi deployment come later. ## Run locally @@ -15,12 +15,23 @@ ```sh cp .env.example .env -# Set CRIBD_RTSP_URL in .env. +# Set the camera URL in .env. ./bin/cribd ``` -Open `http://localhost:8889/crib`. The viewer reports when the camera is connecting, live, or offline, and reconnects after interruptions or frozen video. Use H.264 video with Opus, G722, PCMA, or PCMU audio for WebRTC playback. +`CRIBD_ADAPTER` defaults to `direct`. Use it when the camera already supplies H.264 video with browser-compatible audio such as Opus, G722, PCMA, or PCMU. +For a Reolink H.264 stream with AAC audio, use: + +```sh +CRIBD_ADAPTER=reolink +CRIBD_RTSP_URL=rtsp://user:pass@camera/stream +``` + +The Reolink adapter copies video without decoding it and converts audio to 48 kHz Opus. H.265 streams are not supported. + +Open `http://localhost:8889/crib`. The viewer reports when the camera is connecting, live, or offline, and reconnects after interruptions or frozen video. + To view from another device, use the Mac's LAN IPv4 address—not the camera's: ```sh @@ -34,11 +45,11 @@ ## Architecture ```text -camera -> RTSP -> cribd/MediaMTX -> WebRTC -> viewer -camera -> vendor event API -> optional adapter -> generic events -> cribd +camera -> stream adapter -> RTSP -> MediaMTX -> WebRTC -> viewer +camera -> vendor event API -> event adapter -> generic events -> cribd ``` -The media path is required and independent of adapters. Adapter failures must never interrupt video or audio. +The selected stream adapter supplies MediaMTX with browser-compatible media. Event support is separate; event adapter failures must never interrupt video or audio. ### Core @@ -47,15 +58,11 @@ - Report camera, stream, and server health. - Accept generic events when an adapter is configured. -### Optional hardware adapter +### Stream adapters -- Authenticate with the camera's event API. -- Subscribe and reconnect independently of the media path. -- Discover capabilities such as motion or crying. -- Translate vendor data into generic events. +- `direct` passes a compatible RTSP stream to MediaMTX unchanged. +- `reolink` copies H.264 video and converts AAC audio to Opus inside MediaMTX's FFmpeg image. -The core does not know how Reolink or another vendor delivers events. Without an adapter, event features are unavailable. - ## Constraints - Local viewing must work without public internet access. @@ -69,7 +76,7 @@ 1. Test a dedicated camera, night vision, audio, and restart recovery. 2. Move the stack to a Raspberry Pi and add automatic startup. -3. Add Tailscale, define the event interface, and build a Reolink adapter. +3. Add Tailscale and define the event interface. ## License diff --git a/adapters/reolink/stream b/adapters/reolink/stream @@ -0,0 +1,24 @@ +#!/bin/sh + +set -eu + +: "${CRIBD_RTSP_URL:?CRIBD_RTSP_URL is required}" +: "${RTSP_PORT:?RTSP_PORT is required}" +: "${MTX_PATH:?MTX_PATH is required}" + +exec ffmpeg \ + -nostdin \ + -hide_banner \ + -loglevel quiet \ + -rtsp_transport tcp \ + -rw_timeout 5000000 \ + -i "$CRIBD_RTSP_URL" \ + -map 0:v:0 \ + -map 0:a:0 \ + -c:v copy \ + -c:a libopus \ + -ar 48000 \ + -b:a 96k \ + -f rtsp \ + -rtsp_transport tcp \ + "rtsp://127.0.0.1:$RTSP_PORT/$MTX_PATH" diff --git a/bin/cribd b/bin/cribd @@ -18,9 +18,15 @@ started= log_pid= -if [ "${CRIBD_RTSP_URL+x}" != x ] && [ -f "$project_dir/.env" ]; then +# Prefix exported overrides so empty values still take precedence. +rtsp_override=${CRIBD_RTSP_URL+x}${CRIBD_RTSP_URL-} +adapter_override=${CRIBD_ADAPTER+x}${CRIBD_ADAPTER-} + +if [ -f "$project_dir/.env" ]; then . "$project_dir/.env" fi +[ -z "$rtsp_override" ] || CRIBD_RTSP_URL=${rtsp_override#x} +[ -z "$adapter_override" ] || CRIBD_ADAPTER=${adapter_override#x} case "${CRIBD_RTSP_URL-}" in rtsp://* | rtsps://*) rtsp_url=$CRIBD_RTSP_URL ;; @@ -28,8 +34,24 @@ *) error "CRIBD_RTSP_URL must use rtsp:// or rtsps://." ;; esac -unset CRIBD_RTSP_URL CRIBD_HOST +adapter=${CRIBD_ADAPTER:-direct} +case "$adapter" in + direct) + media_image=docker.io/bluenviron/mediamtx:1.20.0 + MTX_PATHS_CRIB_SOURCE=$rtsp_url + ;; + reolink) + media_image=docker.io/bluenviron/mediamtx:1.20.0-ffmpeg + MTX_PATHS_CRIB_SOURCE=publisher + [ -x "$project_dir/adapters/reolink/stream" ] || + error "Reolink adapter is missing or not executable." + ;; + *) error "CRIBD_ADAPTER must be 'direct' or 'reolink'." ;; +esac +unset CRIBD_RTSP_URL CRIBD_ADAPTER CRIBD_HOST \ + rtsp_override adapter_override + container system start for name in "$media_name" "$viewer_name"; do @@ -65,13 +87,27 @@ trap 'exit 130' 2 trap 'exit 143' 15 -container run --detach --rm --name "$media_name" \ - --env "MTX_PATHS_CRIB_SOURCE=$rtsp_url" \ +export MTX_PATHS_CRIB_SOURCE + +set -- --detach --rm --name "$media_name" \ + --env MTX_PATHS_CRIB_SOURCE \ --env "MTX_WEBRTCADDITIONALHOSTS=$host" \ --publish "$host:8890:8889/tcp" \ - --publish "$host:8189:8189/udp" \ - docker.io/bluenviron/mediamtx:1.20.0 >/dev/null + --publish "$host:8189:8189/udp" + +if [ "$adapter" = reolink ]; then + CRIBD_RTSP_URL=$rtsp_url + export CRIBD_RTSP_URL + set -- "$@" \ + --env CRIBD_RTSP_URL \ + --env MTX_PATHS_CRIB_RUNONINIT=/adapter/stream \ + --env MTX_PATHS_CRIB_RUNONINITRESTART=true \ + --mount "type=bind,source=$project_dir/adapters/reolink,target=/adapter,readonly" +fi + +container run "$@" "$media_image" >/dev/null started=$media_name +unset CRIBD_RTSP_URL MTX_PATHS_CRIB_SOURCE rtsp_url container run --detach --rm --read-only --name "$viewer_name" \ --mount "type=bind,source=$project_dir/web,target=/www,readonly" \ diff --git a/changelog/2026-08-13-camera-adapters.md b/changelog/2026-08-13-camera-adapters.md @@ -0,0 +1,9 @@ +# Camera Adapters + +Date: **AUG.13.2026** + +`cribd` accepts browser-compatible streams from camera adapters. + +The Reolink adapter copies H.264 video and converts AAC audio to Opus before publishing a local RTSP stream to `cribd`. Cameras that already provide H.264 and Opus pass through unchanged. + +Stream and event support are separate adapter capabilities. `cribd` remains responsible for delivering normalized media over WebRTC. |