A sane Octoprint (octopi) USB camera daemon

Octoprint is neat. However, the USB/webcamera support is a bit obtuse — especially when you throw haproxy into the mix.

The Octoprint documentation recommends using mjpg-streamer as a standalone daemon to convert a v4l video stream into a HTTP stream … and use haproxy to selectively redirect traffic to that stream when an arbitrary value prepends the HTTP URI.

There are a few issues:

  • The recommended haproxy.cfg isn’t compatible with current versions of haproxy,
  • Octoprint appends a seemingly-random session ID to the camera URI, which confuses the hell out of mjpg-streamer,
  • mjpg-streamer doesn’t appear to handle multiple simultaneous streams, resulting in the infuriating “403: Forbidden! frame already sent” error,
  • mjpg-streamer itself is complete overkill here.

Wanting this to work, I looked around for a simpler scheme. I came across Igor Maculan’s “Simple Python Motion Jpeg” daemon (https://gist.github.com/n3wtron/4624820), which looked promising.

I spent a few hours this morning porting it to python 3.x, fixing a few bugs, and adding command-line tunables. It works, and it works well. It is available on GitHub at https://github.com/christopherkobayashi/octoprint-stuff/blob/main/webcam.py

Below is a working haproxy.cfg that handles SSL:

global
	maxconn		20000
	log		127.0.0.1 local0
	user		haproxy
	chroot		/usr/share/haproxy
	pidfile		/run/haproxy.pid
	daemon

defaults 
	timeout		connect 5s
	timeout		client 1m
	timeout		server 1m

frontend public_ssl
	bind		:::443 v4v6 ssl crt /etc/letsencrypt/live/both.pem
	use_backend	webcam if { path_beg /webcam/ }
	default_backend	octoprint

backend octoprint
	mode		http
	http-request	replace-uri '^([^\ :]*)\ /(.*)' '\1 /\2'
	option		forwardfor
	server		octoprint1 127.0.0.1:5000

backend webcam
	mode		http
	http-request	replace-uri '^([^\ :]*)\/webcam/(.*)$' '\1/\2'
        server webcam	127.0.0.1:8080

The Octoprint web camera URL should be “https://${SERVER_NAME}/webcam/${SOMETHING}.mjpg”. ${SOMETHING}.mjpg can be anything, actually … webcam.py will respond to any request with a MJPEG stream.

I hope this saves time for others banging their heads against Octoprint’s … interesting camera support scheme.

About Chris Kobayashi

I'm a security systems engineer, specializing in UNIX, network, and physical security. I'm in Tokyo, and I'm mostly retired now. I'm well-versed in both electrical and software engineering, with a particular interest in old computers and game consoles. You can contact me here.
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.