RTSP Camera¶
The RTSP Camera sensor captures H264 video streams from IP cameras and publishes them to the Zenoh message bus.
Overview¶
| Property | Value |
|---|---|
| Binary | rtsp_camera_node |
| Config File | config.yaml |
| Output | CompressedImage (H264) + RawImage (RGBA over SHM) |
| Topic Pattern | bubbaloop/global/{machine_id}/{name}/compressed |
Features¶
- Zero-copy H264 passthrough — No decoding on the compressed path, minimal CPU usage
- Multi-instance support — Run multiple cameras as separate instances of the same binary
- SPS/PPS injection — Stream compatibility for web decoding
- Raw RGBA over SHM — Decoded frames published via shared memory for local consumers
- Hardware acceleration — NVIDIA NVDEC (Jetson) or CPU fallback
- Configurable latency and frame rate — Balance between delay and throughput
Architecture¶
flowchart LR
subgraph RTSP["RTSP Camera"]
cam[IP Camera]
end
subgraph GStreamer["GStreamer Pipeline"]
rtspsrc[rtspsrc]
depay[rtph264depay]
parse[h264parse]
sink[appsink]
end
subgraph Node["Camera Node"]
zenoh[Zenoh Publisher]
end
cam -->|RTSP/RTP| rtspsrc
rtspsrc --> depay
depay --> parse
parse --> sink
sink -->|H264 NAL units| zenoh
Configuration¶
Basic Configuration¶
Each camera instance has its own config.yaml:
Configuration Fields¶
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string | Yes | — | Unique instance name (used in topic path and health) |
url |
string | Yes | — | Full RTSP URL with credentials |
latency |
integer | No | 200 |
Buffer latency in milliseconds (1-10000) |
frame_rate |
integer | No | — | Target publish rate in FPS (1-120, unlimited if unset) |
raw_width |
integer | No | 560 |
Width of raw RGBA frames (SHM path) |
raw_height |
integer | No | 560 |
Height of raw RGBA frames (SHM path) |
hw_accel |
string | No | nvidia |
Hardware acceleration: nvidia (Jetson NVDEC) or cpu |
RTSP URL Format¶
Examples:
# With authentication
url: "rtsp://admin:password123@192.168.1.100:554/stream1"
# Without authentication
url: "rtsp://192.168.1.100:554/live"
# Non-standard port
url: "rtsp://camera.local:8554/h264"
Multi-Camera Setup¶
Each camera runs as a separate instance of the same binary. Register each with a unique name and config:
bubbaloop node instance rtsp-camera entrance --config configs/entrance.yaml --start
bubbaloop node instance rtsp-camera parking --config configs/parking.yaml --start
bubbaloop node instance rtsp-camera lobby --config configs/lobby.yaml --start
Each config file is a single camera:
# configs/entrance.yaml
name: entrance
url: "rtsp://admin:pass@192.168.1.100:554/stream2"
latency: 200
# configs/parking.yaml
name: parking
url: "rtsp://admin:pass@192.168.1.101:554/stream2"
latency: 200
hw_accel: cpu
Running¶
Start Camera Node¶
# Via daemon (recommended)
bubbaloop node start rtsp-camera
bubbaloop node logs rtsp-camera -f
# Direct (for development)
pixi run main -- -c config.yaml -e tcp/127.0.0.1:7447
CLI Options¶
| Option | Description |
|---|---|
-c, --config |
Path to configuration YAML file |
-e, --endpoint |
Zenoh router endpoint |
Environment Variables¶
| Variable | Description |
|---|---|
BUBBALOOP_ZENOH_ENDPOINT |
Override Zenoh endpoint (default: tcp/127.0.0.1:7447) |
BUBBALOOP_MACHINE_ID |
Machine identifier (default: hostname) |
RTSP_URL |
Override RTSP URL from config (useful for Docker/env-based deployments) |
RUST_LOG |
Logging level (info, debug, trace) |
Topics¶
Published Topics¶
| Topic | Type | Description |
|---|---|---|
bubbaloop/global/{machine_id}/{name}/compressed |
CompressedImage |
H264 compressed frames (network-visible) |
bubbaloop/local/{machine_id}/{name}/raw |
RawImage |
RGBA decoded frames (SHM-only, same machine) |
Topic Format¶
The topic key is derived from the name config field. If the name ends with _camera, the suffix is stripped:
name: tapo_entrance_camera→ topics attapo_entrance/compressedandtapo_entrance/rawname: front_door→ topics atfront_door/compressedandfront_door/raw
Example: Camera named tapo_terrace on machine nvidia_orin00 publishes to:
bubbaloop/global/nvidia_orin00/tapo_terrace/compressed (H264, network-visible)
bubbaloop/local/nvidia_orin00/tapo_terrace/raw (RGBA, SHM-only)
Message Format¶
CompressedImage¶
| Field | Type | Description |
|---|---|---|
header |
Header | Timestamp and metadata |
format |
string | Always "h264" |
data |
bytes | H264 NAL units (Annex B) |
See Camera API for the full protobuf definition.
Header Fields¶
| Field | Description |
|---|---|
acq_time |
Frame acquisition timestamp (nanoseconds) |
pub_time |
Message publication timestamp (nanoseconds) |
sequence |
Frame sequence number |
frame_id |
Camera instance name |
machine_id |
Machine identifier (e.g., nvidia_orin00) |
Performance¶
CPU Usage¶
The camera node uses zero-copy H264 passthrough:
| Operation | CPU Impact |
|---|---|
| RTSP receive | Minimal (network I/O) |
| H264 parsing | Near zero (no decode) |
| Protobuf serialization | Minimal |
| Zenoh publish | Minimal |
Memory Usage¶
| Cameras | Typical Memory |
|---|---|
| 1 | ~10-20 MB |
| 4 | ~40-80 MB |
| 8 | ~80-160 MB |
Latency¶
| Setting | Typical Latency |
|---|---|
latency: 100 |
~150-200ms end-to-end |
latency: 200 |
~250-350ms end-to-end |
latency: 500 |
~550-700ms end-to-end |
Stream Selection¶
Many IP cameras offer multiple streams:
| Stream | Path | Resolution | Bandwidth | Use Case |
|---|---|---|---|---|
| Main | /stream1 |
1080p/4K | High | Recording |
| Sub | /stream2 |
480p/720p | Low | Monitoring |
Use sub-streams for real-time monitoring
Sub-streams reduce bandwidth and improve stability for multi-camera setups.
Troubleshooting¶
Camera not connecting¶
- Verify the RTSP URL is correct
- Test with VLC:
vlc rtsp://... - Check firewall allows RTSP (port 554)
- Verify credentials
High latency¶
- Reduce
latencyconfiguration value - Use sub-stream instead of main stream
- Check network bandwidth
- Use wired connection for multiple cameras
Dropped frames¶
- Increase
latencyconfiguration value - Reduce number of simultaneous cameras
- Check network congestion
- Verify camera isn't overloaded
"Waiting for keyframe" in dashboard¶
- Wait a few seconds for the next keyframe
- Verify camera is streaming H264 (not H265/HEVC)
- Check
bubbaloop node logs rtsp-camerafor errors
Next Steps¶
- Camera Panel — View camera streams
- Camera API — Message format details
- Configuration — Full configuration reference