WebCams and Pi Clones
This started as “how do I stream a web cam without having to build anything”
I wanted to try and avoid building mjpeg-streamer and just use off-the shelf software to get a webcam up and running. I soon discovered why you should use mjpeg-streamer
FFMPEG, NGINX and RTMP
Let’s assume you have NGINX already setup and running and you have a default website. We can allow Nginx to host an RTMP stream, and have that coming from ffmpeg
RTMP and NGINX
1
sudo apt-get install libnginx-mod-rtmp
This should create a symlink in /etc/nginx/modules-enabled to the rtmp module for nginx
We will create a second link in this folder for our RTMP host
1
sudo vi /etc/nginx/modules-available/rtmp.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
rtmp {
server {
listen 1935;
chunk_size 4096;
allow publish 127.0.0.1;
deny publish all;
application webcam {
live on;
record off;
}
}
}
Restart NGINX and we should be ready to host a stream
1
2
sudo systemctl restart nginx
sudo ln -s /etc/nginx/modules-available/rtmp.conf /etc/nginx/modules-enabled/99-rtmp.conf
finally, make a note of the external IP of this device
1
ip address
1
2
3
2: end0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group
...
inet 192.168.100.176/24 brd 192.168.100.255 scope global dynamic end0
FFMPEG
We will need the video4linux tools, as we will be using those libraries to make our life easier
1
sudo apt-get install ffmpeg v4l-utils
now lets find our video device
1
lsusb
Tells me my connected devices:
1
2
3
4
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub
Bus 001 Device 003: ID 046d:085c Logitech, Inc. C922 Pro Stream Webcam
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
and we can inspect the video devices:
1
v4l2-utils --list-devices
Which lists many devices, including the webcam I’m looking for
1
2
3
4
C922 Pro Stream Webcam (usb-0000:01:00.0-1.1):
/dev/video0
/dev/video1
/dev/media0
let’s plug that into ffmpeg and publish a stream:
1
ffmpeg -f v4l2 -i /dev/video0 -c:v libx264 -an -f flv rtmp://127.0.0.1/webcam/live;
This will run until the stream is killed (ctrl-C)
Testing
We can use VLC to test the stream is working as we expect
rtmp://192.168.100.176/webcam/live (the IP address we identified earlier)
If all is well, you should see a stream of the data from the webcam
If you are struggling to get output (I did), then you can add hls streaming which seemed to work a little more reliably
hls and dash support
We need to do a few things for a good hls stream:
1) Setup a tmpfs space for the data to drop into without killing our hard drive - RAM space would be good for this 2) Setup an endpoint to expose HLS and DASH data
We can use existing /tmp space and create a folder there to host our streamed data
1
sudo mkdir /tmp/stream
Then we can extend our rtmp config to expose hls and dash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
rtmp {
server {
listen 1935;
chunk_size 4096;
allow publish 127.0.0.1;
deny publish all;
application webcam {
live on;
record off;
hls on;
hls_path /tmp/stream/hls;
hls_fragment 1s;
hls_playlist_length 5s;
dash on;
dash_path /tmp/stream/dash;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
server {
listen 8088;
location / {
add_header Access-Control-Allow-Origin *;
root /tmp/stream;
}
}
types {
application/dash+xml mpd;
}
Remember to restart NGINX
1
sudo systemctl restart nginx
Now we can start ffmpeg
1
ffmpeg -f v4l2 -i /dev/video0 -c:v libx264 -an -f flv rtmp://127.0.0.1/webcam/live;
And point VLC at http://192.168.100.176:8088/hls/live.m3u8
Summary
While running ffmpeg, connect a second terminal and take a look at CPU usage - this is where we find the first limitation. You can enable the mali GPU by editing /boot/armbainEnv.txt to add overlays=gpu to the list, but this does not fully solve the problem. While the CPU load did drop, there’s still a fundamental issue with the whole stream lagging by several seconds and that makes it tougher to use for my intended use case (webcam for monitoring my 3D printer)
Before adding the gpu overlay, klipper would stall and stop running. Somewhat fatal. With the gpu overlay enabled and h264_vaapi CPU usage dropped to 80%, but still felt risky for running klipper.
At this point, I realised this is a bit of a lost cause. So I switched my attention to running this on a genuine raspberry pi and instead opted to use mjpeg-streamer
Building mjpeg-streamer
https://github.com/jacksonliam/mjpg-streamer
Following the instructions on the mjpg-streamer github page, I quickly hit a few snags
Here’s how I built for for Debian Trixie
1
2
3
4
5
6
7
8
sudo apt-get install cmake gcc g++
sudo apt-get install libjpeg62-turbo-dev
cd ~
git clone https://github.com/jacksonliam/mjpg-streamer.git
cd mjpg-streamer/mjpg-streamer-experimental
make distclean
make
sudo make install
From here, we can feed in our camera device and check that the stream is working
1
/usr/local/bin/mjpg_streamer -i "input_uvc.so -r 1280x720 -d /dev/video0" -o "output_http.so -w /usr/local/share/mjpg-streamer/www"
Open our browser at http://192.168.100.179:8080/ and we should see the default stream demo pages
We can jump to the moonraker webcam configuration tools by adding the upstream config for klipper and moonraker
1
2
3
4
5
6
...
upstream mjpgstreamer1 {
ip_hash;
server 127.0.0.1:8080;
}
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
...
server {
...
location /webcam/ {
postpone_output 0;
proxy_buffering off;
proxy_ignore_headers X-Accel-Buffering;
access_log off;
error_log off;
proxy_pass http://mjpgstreamer1/;
}
...
}
...
Now you can open up your 3D Printer Mainsail web page, go to “Settings” cogs in the top right of the page and down to “Webcams” and “Add” a cam.
1
2
3
4
Name: PrintCam
URL Stream: /webcam/?action=stream
URL Snapshot: /webcam/?action=snapshot
Service: MJPEG-Streamer