Technical note
用OctoPrint和Restreamer远程查看3D打印机
OctoPrint已经可以远程控制3D打印机,但手头的网络摄像头只提供RTSP。浏览器不能直接播放RTSP,OctoPrint的Classic Webcam兼容层需要MJPEG流和一张可以单独请求的快照,于是在两者之间增加了Restreamer。
数据链路很简单:摄像头通过RTSP把视频交给Restreamer,Restreamer再向OctoPrint提供浏览器能够访问的流和快照。打印机串口仍然由OctoPrint直接管理,视频转码服务不接触打印控制。
参考
OctoPrint容器
OctoPrint官方镜像需要持久化/octoprint,并把打印机串口映射进容器。下面以常见的/dev/ttyACM0为例,实际设备名可以先通过ls -l /dev/serial/by-id/确认:
services:
octoprint:
image: octoprint/octoprint:latest
container_name: octoprint
restart: unless-stopped
ports:
- "8081:80"
devices:
- /dev/ttyACM0:/dev/ttyACM0
volumes:
- octoprint-data:/octoprint
volumes:
octoprint-data:
docker compose up -d
docker compose logs -f octoprint
如果摄像头是USB设备,OctoPrint官方镜像可以映射/dev/video0并启用内置MJPG-Streamer。这里使用的是独立网络摄像头,不需要把视频设备交给OctoPrint容器。
只为RTSP输入启动Restreamer
Restreamer官方示例默认开放HTTP、HTTPS、RTMP、RTMPS和SRT端口。这个场景只从局域网摄像头拉取RTSP,再给OctoPrint提供HTTP地址,因此先开放管理和播放使用的8080端口即可:
services:
restreamer:
image: datarhei/restreamer:latest
container_name: restreamer
restart: unless-stopped
ports:
- "192.0.2.10:8080:8080"
volumes:
- ./config:/core/config
- ./data:/core/data
192.0.2.10是文档示例地址,部署时改成Restreamer主机实际使用的局域网地址。这样不会把8080监听到所有网卡;如果OctoPrint和Restreamer在同一台机器上,也可以只绑定127.0.0.1。
mkdir -p config data
docker compose up -d
docker compose logs -f restreamer
容器运行后打开http://<Restreamer主机>:8080/ui,设置独立的管理密码,再通过向导添加网络视频源。RTSP地址和摄像头凭据直接填入Restreamer,不写进Compose文件或OctoPrint配置。
网络RTSP输入不需要访问宿主机摄像头设备,因此也不需要--privileged。早期在LXC中出现过AppArmor与runc权限错误,但把LXC改成unconfined、屏蔽AppArmor状态或给容器放开seccomp都会扩大权限,不适合作为通用解决办法。无法在受限LXC中正常运行时,换成具备标准Docker能力的虚拟机或主机更省事。
找到MJPEG流和快照
Restreamer界面可以复制HLS与Snapshot地址。Snapshot可以直接交给OctoPrint;HLS地址通常以.m3u8结尾,不能直接填进Classic Webcam的Stream URL,因为OctoPrint兼容层要求MJPEG。
当时使用的Restreamer版本还提供了这个MJPEG地址:
http://192.0.2.10:8080/stream.mjpg?type=mjpeg
这个路径没有出现在当前Restreamer文档中,升级后不能默认它仍然存在。填写OctoPrint之前,先检查响应类型:
curl -sS --max-time 5 \
-D - -o /dev/null \
'http://192.0.2.10:8080/stream.mjpg?type=mjpeg'
MJPEG响应的Content-Type应为multipart/x-mixed-replace一类的多段图片流。如果返回HTML、JSON、404或普通HLS内容,就不能把它当作OctoPrint视频源;此时应改用明确支持RTSP转MJPEG的服务,而不是把.m3u8硬填进去。
Snapshot地址包含Restreamer生成的通道标识,直接从界面复制,避免把示例中的固定UUID当成自己的地址。可以先确认它返回图片:
curl -sS --max-time 5 \
-D - -o /dev/null \
'http://192.0.2.10:8080/memfs/<通道标识>.jpg'
这里的<通道标识>只是占位说明,执行前必须替换。响应的Content-Type应是image/jpeg或其他实际图片类型。
填入OctoPrint
在OctoPrint的Webcam设置中填写:
- Stream URL:已经确认可用的MJPEG地址;
- Snapshot URL:Restreamer界面复制出的快照地址;
- Path to FFMPEG:容器镜像内使用
/usr/bin/ffmpeg; - Stream aspect ratio:按摄像头实际画面选择
16:9或4:3。
浏览器和OctoPrint服务端都要能访问这些地址。Stream URL由浏览器加载,而Snapshot通常由OctoPrint在生成延时摄影时请求;只在某一端能解析的主机名会造成“控制页有画面但快照失败”,或反过来。
不把摄像头跟着OctoPrint暴露到公网
OctoPrint的登录权限不会自动保护外部摄像头地址。官方文档明确说明,OctoPrint只是嵌入视频流,知道摄像头URL的人仍可能绕过OctoPrint直接观看。
因此Restreamer和摄像头都只保留在可信网络中,通过VPN访问最简单。确实需要反向代理时,应单独为视频流增加认证和HTTPS,并确认浏览器不会因为OctoPrint页面是HTTPS、视频地址是HTTP而拦截混合内容。摄像头原始RTSP密码一旦出现在日志、截图或旧配置中,也应立即更换。