Last Updated on October 5, 2022.
After my recent move, the streaming and ‘workshop/den/laboratory’ setup has been a lot of work from the ground up on the computer system side. I used to have a Raspberry PI 4 used as a remote webcam that covered my old place’s 3D printing area. While that worked, I never liked the idea of dedicating a whole Raspberry Pi 4 to that – I wanted to try a Raspberry Pi Zero W and see if it could handle the load. Utilizing the popular MJPG-Streamer package, I was able to get that installed and running, though I had a few hiccups which I’ll reference at the bottom.
The article is a combination of various articles I found on the web, referencing older versions of one part or another, and this is a reference for my setup should I need to rebuild it.
Hardware
- Raspberry Pi Zero W – Purchased one of those kits on Amazon and it came with various cases and cables I needed, so I was happy with it.
- Logitech USB Webcam
- Power/HDMI/USB
- Keyboard/Mouse
Fresh Raspbian Install
I’m utilizing the latest version of Raspbian as of this writing, which was released around February, 2020. Flashing that to a simple 16 GB Micro SD Card for a blank slate:
Assuming you’re relatively familiar with the Pi, here’s the minimum I’m generally doing as post boot up task work:
- Changing default password
- Setting Up Wifi
- Enabling SSH
- Setting Hostname
- Setting Locale/Internationalization Options
- Rebooting
After that, the obligatory ‘update’ install:
sudo apt update
sudo apt upgrade
I can now SSH into the Pi Zero W, disconnect the keyboard, and move along with the install.
Build Dependencies
We need to download some things first before we can build mjpg-streamer. I found some references to articles that pulled from the SVN repo to retrieve and compile, but I ended up getting a large amount of compile errors that look like some library was swapped but the source wasn’t updated. It’s the 'redefinition of ‘struct statx_timestamp’'
error.
Instead of pulling the SVN version, I’m going to be pulling the Git repo of mjpg-streamer that was created by jacksonliam. This (https://github.com/jacksonliam/mjpg-streamer) is the ‘official’ successor to the now abandoned SVN version at https://sourceforge.net/projects/mjpg-streamer/.
We’ll now install our dependencies before we download and compile mjpg-streamer code:
sudo apt-get install build-essential libjpeg9-dev imagemagick libv4l-dev cmake git -y
Git, Make, Install
mkdir ~/mjpg-streamer
cd ~/mjpg-streamer
git clone https://github.com/jacksonliam/mjpg-streamer.git
cd mjpg-streamer/mjpg-streamer-experimental
make
sudo make install
The make install will copy binaries, libraries and the www pages to the /usr/local/ directory structure:
/usr/local/bin/mjpg_streamer
– The primary binary/usr/local/lib/mjpg-streamer/
– The directory of input/output modules/usr/local/share/mjpg-streamer/www
– The www server interface
Test The Build
I’m going to test the build by plugging in a webcam into the Pi Zero W’s lone USB port. Executing dmesg shows that it was loaded properly:
[ 1275.662775] usb 1-1: New USB device found, idVendor=046d, idProduct=082d, bcdDevice= 0.11
[ 1275.662796] usb 1-1: New USB device strings: Mfr=0, Product=2, SerialNumber=1
[ 1275.662806] usb 1-1: Product: HD Pro Webcam C920
Let’s test by trying to run mjpg-streamer against the input_uvc.so plugin, since I”m not using a Raspi-Camera, but a USB one instead. (See notes at the bottom about Raspberry Pi Bullseye and Raspi-Cameras). I’ll also output using the http plugin. So my testing command line looks like this:
/usr/local/bin/mjpg_streamer -i "input_uvc.so -f 15 -r 640x480" \
-o "output_http.so -w /usr/local/share/mjpg-streamer/www"
Executing that line gives us a dump of data – here’s the relevant info:
MJPG Streamer Version: git rev: 5a6e0a2db163e6ae9461552b59079870d0959340
i: Using V4L2 device.: /dev/video0
i: Desired Resolution: 640 x 480
i: Frames Per Second.: 15
i: Format............: JPEG
i: TV-Norm...........: DEFAULT
o: www-folder-path......: /usr/local/share/mjpg-streamer/www/
o: HTTP TCP port........: 8080
o: HTTP Listen Address..: (null)
o: username:password....: disabled
o: commands.............: enabled
Our key variables to tweak are -f for frame rate, and -r for resolution. I’ll change those later, but for a quick test I head on out to my browser and point it at the www server at http://cam-pi-zero.local:8080/
Not only do we see the web interface, but a snapshot of the web cam, which was, clearly, laying down on a workbench behind me while I tried this out.
Validating the stream worked (by clicking ‘Stream’) and turning around, I could see myself moving:
You can now hit CTRL-C in your SSH window (or terminal) and quit the stream. After this point, I could delete the build files I downloaded.
Tweaking configuration
I wanted to run my camera at its intended resolution and at least a frame rate of 30fps. To do that I modified my command line:
#30fps, 1080 HD
/usr/local/bin/mjpg_streamer -i "input_uvc.so -f 30 -r 1920x1080" \
-o "output_http.so -w /usr/local/share/mjpg-streamer/www"
I then loaded my own stream up in VLC by opening the direct network path to the stream:
http://cam-pi-zero.local:8080?action=stream
That worked, and I get about a 1-2 second delay from Pi to VLC. So I wouldn’t use this with audio feeds unless I was planning on creating a sync delay. I’m using this to monitor 3D prints, or watch birds outside, so my use case does not demand low latency. Is it exactly 30 frames per second? No…. NO it’s not.
At 1280×720, it seemed closer, but at 1920×1080, when set at 30fps, it definitely wasn’t even close. I’d guess more like 15.
The PI wasn’t maxed out on CPU, but it could just be the nature of USB 2.0 at this point. I’m not sure how I can tell if it’s overloaded there or not, but, once again, this is a light monitoring video stream, I don’t care too much about latency. It could be WiFi as well. Someday I may dig in a bit more and find out where the bottleneck is.
I think you could probably choose either 1920×1080 15fps or 1280×720 30fps routes and be okay.
v4l2-ctl --list-formats-ext
Running On Startup
I liked Jacob Salmela‘s script – all I did was change it for my command line on the stop and restart section for my resolution and frame-rate. Save the following script by doing a sudo vi:
sudo vi /etc/init.d/livestream.sh
#!/bin/sh
# /etc/init.d/livestream.sh
### BEGIN INIT INFO
# Provides: livestream.sh
# Required-Start: $network
# Required-Stop: $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: mjpg_streamer for webcam
# Description: Streams /dev/video0 to http://IP/?action=stream
### END INIT INFO
f_message(){
echo "[+] $1"
}
# Carry out specific functions when asked to by the system
case "$1" in
start)
f_message "Starting mjpg_streamer"
/usr/local/bin/mjpg_streamer -b -i "input_uvc.so -f 15 -r 1920x1080" -o "output_http.so -w /usr/local/share/mjpg-streamer/www"
sleep 2
f_message "mjpg_streamer started"
;;
stop)
f_message "Stopping mjpg_streamer…"
killall mjpg_streamer
f_message "mjpg_streamer stopped"
;;
restart)
f_message "Restarting daemon: mjpg_streamer"
killall mjpg_streamer
/usr/local/bin/mjpg_streamer -b -i "input_uvc.so -f 15 -r 1920x1080" -o "output_http.so -w /usr/local/share/mjpg-streamer/www"
sleep 2
f_message "Restarted daemon: mjpg_streamer"
;;
status)
pid=`ps -A | grep mjpg_streamer | grep -v "grep" | grep -v mjpg_streamer. | awk ‘{print $1}’ | head -n 1`
if [ -n "$pid" ];
then
f_message "mjpg_streamer is running with pid ${pid}"
f_message "mjpg_streamer was started with the following command line"
cat /proc/${pid}/cmdline ; echo ""
else
f_message "Could not find mjpg_streamer running"
fi
;;
*)
f_message "Usage: $0 {start|stop|status|restart}"
exit 1
;;
esac
exit 0
Then we enable this on startup by performing:
sudo chmod 755 /etc/init.d/livestream.sh
sudo update-rc.d livestream.sh defaults
Now you can reboot your pi, or use commands like ‘sudo service livestream start’ I rebooted my pi, and my fed was running, and running a status command on my service yields:
pi@cam-pi-zero:~ $ sudo service livestream status
● livestream.service - LSB: mjpg_streamer for webcam
Loaded: loaded (/etc/init.d/livestream.sh; generated)
Active: active (running) since Thu 2020-05-14 11:46:09 CDT; 2min 51s ago
Docs: man:systemd-sysv-generator(8)
Process: 411 ExecStart=/etc/init.d/livestream.sh start (code=exited, status=0/SUCCESS)
Memory: 2.2M
CGroup: /system.slice/livestream.service
└─416 /usr/local/bin/mjpg_streamer -b -i input_uvc.so -f 15 -r 1920x1080 -o output_http.so
May 14 11:46:07 cam-pi-zero.local mjpg_streamer[416]: MJPG-streamer [416]: TV-Norm...........: DEFAUL
May 14 11:46:08 cam-pi-zero.local mjpg_streamer[416]: MJPG-streamer [416]: www-folder-path......: /us
May 14 11:46:08 cam-pi-zero.local mjpg_streamer[416]: MJPG-streamer [416]: HTTP TCP port........: 808
May 14 11:46:08 cam-pi-zero.local mjpg_streamer[416]: MJPG-streamer [416]: HTTP Listen Address..: (nu
May 14 11:46:08 cam-pi-zero.local mjpg_streamer[416]: MJPG-streamer [416]: username:password....: dis
May 14 11:46:08 cam-pi-zero.local mjpg_streamer[416]: MJPG-streamer [416]: commands.............: ena
May 14 11:46:08 cam-pi-zero.local mjpg_streamer[416]: MJPG-streamer [416]: starting input plugin inpu
May 14 11:46:08 cam-pi-zero.local mjpg_streamer[416]: MJPG-streamer [416]: starting output plugin: ou
May 14 11:46:09 cam-pi-zero.local livestream.sh[411]: [+] mjpg_streamer started
May 14 11:46:09 cam-pi-zero.local systemd[1]: Started LSB: mjpg_streamer for webcam.
Conclusion
Using the Raspberry Pi for video streams is good enough if we’re looking for low frame rate monitoring without audio. I’ve yet to find anything that really gives me the frame rate and audio (regardless of latency) that a standard USB webcam directly into my OBS machine would give. Maybe if NDI ever makes it on to the raspberry Pi, or if there is ever SLDP support.
Have you tried streaming across the network on a Raspberry Pi with a USB webcam? Did you fare better than I? Let me know!
Nevertheless, with that, I’m done! I can now embed this into OBS via the VLC media source or anything that can handle an HTTP Motion JPEG video stream. I won’t have audio, but that’s okay for what I’m using this for.
Raspi-Cameras (libcamera is in, raspivid is out in Bullseye)
Mjpg-Streamer won’t have the raspicam input module anymore if you compile on Bullseye, because I believe the headers don’t exist as the Bullseye version is going the way of libcamera. While I was able to hack around that and build it, I got HORRIBLE artifacts using a raspberry pi camera with the h264 codec and libcamera. I tried switching codecs to MJPEG instead of H264 and had less artifacts, but worse frame rate. So for now I decided to go with gstreamer instead of mjpg-streamer at 1280×720 for a nice 30fps solution.
For me, what worked was to enable the legacy raspi-camera support (so we’re not using libcamera, we’re using v4l2).
Here are the rough steps:
- Started out with Bullseye, latest install with sudo apt update/sudo apt upgrade executed.
- Edit /boot/config.txt and change the following:
- start_x=1 //add this line
- gpu_mem=128 //probably no higher
- #camera_auto_detect=1 //Comment this line out
- Restart
- Installs:
sudo apt-get install gstreamer1.0-tools gstreamer1.0-plugins-base \
gstreamer1.0-plugins-good gstreamer1.0-plugins-bad
Then execute this on the command line:
/usr/bin/gst-launch-1.0 v4l2src ! video/x-h264,width=1280,height=720,framerate=30/1 ! h264parse config-interval=1 ! matroskamux streamable=true ! tcpserversink host=::0 port=9000 sync=false sync-method=2
Once that’s up and running, I ran VLC against it using :network-caching=250 and a URL of tcp://<yourhostname>:9000 and was able to get a decent stream. That’s about the extent I’ve been pushing the raspi-cameras as I typically use the USB side. I did notice it was nice and fluid, along with less power consumption by a 100 milliamps or so, so I think I’ll use this as a portable battery powered wireless camera to use around the house on streams. Hmmm, I may need to look at getting a microphone on here somehow and streaming audio with gstreamer as well.
References
- https://einar.slaskete.net/2018/08/16/using-a-raspberry-pi-as-a-surveillance-camera-in-home-assistant/
- https://picamera.readthedocs.io/en/release-1.12/fov.html
- https://qengineering.eu/install-gstreamer-1.18-on-raspberry-pi-4.html
- https://www.raspberrypi.org/documentation/configuration/wireless/wireless-cli.md – Raspberry Pi Document on WIFI Setup
- https://www.amazon.com/Vilros-Raspberry-Starter-Power-Premium/dp/B0748MPQT4 – The Raspberry Pi Zero W kit I purchased
- https://sourceforge.net/projects/mjpg-streamer – The original source forge project.
- https://github.com/jacksonliam/mjpg-streamer – The successor to the abandoned Sourceforge project.
- https://jacobsalmela.com/2014/05/31/raspberry-pi-webcam-using-mjpg-streamer-over-internet/ – Reference for build information
- https://www.acmesystems.it/video_streaming – Another build reference
- https://qiita.com/xeno14/items/e32e52c688d969d182e2 – Another build reference
thankyou – finally a guide that works and give very little lag even on a pi-zerow
Glad it worked out for you! It’s not the best quality or speediest thing in the world but it does get the job done!
how to secure my cam ?
Looks like you have a few options to consider – one is just simple authentication – the second is more of encryption of the stream itself.
* https://medium.com/@petehouston/protect-http-media-stream-created-by-mjpg-streamer-2812efd08f75
* https://crish4cks.net/secure-webcam-streaming-mjpg-streamer-stunnel/
[…] Quelle: MJPG-Streamer on a Raspberry Pi Zero W with a USB Webcam Streaming Setup – Krystof.IO […]
will this work for raspberry pi 3?
I don’t see why not, juni. Nothing here is really Pi Zero specific as far as mjpg streamer. Give it a shot!
thanks also for the quick reply 🙂
You’re welcome – glad you got it figured out!
thanks i already figured it out.
Hi,
First of all, thanks for the nice job you published.
I have a problem and so far I’m not able to solve that problem. I think I did all things right but maybe I overlooked something.
I have a 8Mp sony IMX179 OV5648 CMOS Sensor Usb Camera Module 1/3.2″ Oem witch I try to run on my Raspberry pi W with the help of mjpg-streamer.
The error I get is:
MJPG Streamer Version: git rev: 310b29f4a94c46652b20c4b7b6e5cf24e532af39
i: Using V4L2 device.: /dev/video0
i: Desired Resolution: 640 x 480
i: Frames Per Second.: 15
i: Format…………: JPEG
i: TV-Norm………..: DEFAULT
ERROR opening V4L interface: No such file or directory
i: init_VideoIn failed
Could you please push me in the right direction?
Thanks
Hi Ed – Hmm, it sounds like it doesn’t see your video device (defaulting to /dev/video0) . – if you do an ls in your /dev directory – do you see video0? Or any sort of ‘video’ device? You might need to use lsusb to check what devices are there and see if the pi is detecting it. That’d be my first guess.
Thanks for the response, I will check.
Just FYI Motioneye works perfect with the same camera on a raspberry pi zero
by default it looks for video0. If your device is not plugged into video0, it won’t be found.
This (https://github.com/jacksonliam/mjpg-streamer) is the ‘official’ successor to the now abandoned SVN version at https://sourceforge.net/projects/mjpg-streamer/.
Jacksonliam does not seem to be on github any longer. What is its “official successor”?
Hi Robert,
Try that link again later perhaps – that works for me as of the time of me posting this comment. (https://github.com/jacksonliam/mjpg-streamer) – I’ve just tried it and can see the code base.
Thanks, Eric.
I had set up a different SBC as a webcam server using mjpg-streamer a few years ago, but neglected to record the steps I followed to do it. Happily this page popped up near the top of the Google results, and I was able to zip right through doing it again.
Great, Ran! Glad to see this helped!
I just now did an install on a Pi with the new Bullseye Lite release of the OS. I had to change the libjpeg8-dev to libjpeg9-dev. But it appears that whatever libjpeg features mjpg-streamer uses are completely downward compatible, because it compiled and worked just fine.
I downloaded the source using the recommended clone command:
Maybe you missed a typo in the URL?
Thanks, Ran – I’ll double check and update the guide, appreciate the comment, especially with new versions of Raspbian coming out – things don’t always stay consistent. The eternal struggle of updating.
sudo apt-get install build-essential libjpeg9-dev imagemagick libv4l-dev cmake git -y will do it, just use libjpeg9-dev instead of libjpeg8-dev
Tried that in latest Bullseye, but got:
E: Package ‘libjpeg9-dev’ has no installation candidate
Edit: It works if you leave out the ‘9’.
apt install libjpeg-dev
and accept the two packages offered.
That’s… really strange. I can try and do the reinstall again but I could swear I used the 9. Either way, thank you!
[…] https://krystof.io/mjpg-streamer-on-a-raspberry-pi-zero-w-with-a-usb-webcam-streaming-setup/ […]
Any tips on using the rpi cam – along with the rest of your article regarding having it run on startup?
The latency I’ve noticed is pretty poor (many seconds) – do you think this is due to the tcp usage?
Hi Brett – I used the same startup script skeleton earlier in the article (swapping out the mjpg-streamer commands and references for
gst-launch-1.0
instead) and that worked out well enough.As for latency, I’ll have to boot mine up and do some tests – I have this on a Pi Zero W 2 – I’ve not tried the gstreamer on the Pi Zero W yet. Is that what you’re running? Also, that network-caching argument made a lot of difference – did you try different values on yours?
(I used an original Pi Zero W for the USB mjpg-streamer – but the Pi Zero 2 W is what I used for the gstreamer rpicam)
Great guide. I followed this step by step and it worked without a problem. I’m just getting familiar with raspberry pi, having gotten my first one recently (raspberry pi zero 2w). I have a question: Is this continuously running, or are there commands to stop and restart it?
Thanks, Hector! The gst-launch command runs until you manually kill it – if you want to it to start on bootup, you can look at the launch script in the middle of the document and tailor that for gst-launch instead of mjpg-streamer and install it with the commands I reference there. After that you can do ‘sudo service livestream start’ or sudo service livestream stop’ at will if you want to stop/start it accordingly. If that doesn’t work out, let me know and I can try and see where there’s an issue.
I am trying to do this on a Raspberry Pi 3. If I wanted to open up the browser to view this, would I need to use a different address than http://cam-pi-zero.local:8080/. This seems specific to the zero. Also, can I open this address from a different computer, or would it need to be opened on the pi? Both are on the same network.
Hi Caleb,
Sorry for the late response. You’d use the host name you created for your raspberry pi – if you didn’t set one up that’s raspberrypi.local by default. I just called mine cam-pi-zero, you can name yours whatever you like. As for resolving the host name to an ip address, if you’re on the same network it should work (try with or without the .local), otherwise you can always use the IP address assigned to the raspberry pi.
Does anyone have a way to flip the video in this setup? I’m using a USB webcam, and it’s hanging upside down. I need to flip the stream.
Good question, Ryan – hopefully someone that stops by might have done that – if I have a chance to find out I’ll send you a note.
Hi!
I had to use these as well:
sudo apt install cmake
sudo apt-get install libjpeg-dev
Maybe helps someone.
I tried this on a Raspberry Pi 4 and got lots of strange errors in the kern.log and syslog, and the whole system froze every 2 hours etc.
Raspi-config and change GPU memory to 260GB solved it. Now works as a charm.
In the livestream.sh example (start section) there is typo at line #20 end “-b” that should not be there. All other instructions are 100% 🙂
Thanks, Juha! Removed the little bugger.
[…] https://krystof.io/mjpg-streamer-on-a-raspberry-pi-zero-w-with-a-usb-webcam-streaming-setup/ […]
Thank for your setup guide. So easy to follow even for someone like me who has very little knowledge of Raspberry Pi environment. I now have webcam streaming through a Pi 4B.
The only thing I had to change was
sudo
apt-get
install
build-essential libjpeg9-dev imagemagick libv4l-dev cmake git -y
To
sudo apt-get install build-essential libjpeg62-turbo-dev imagemagick libv4l-dev cmake git -y
The terminal prompted me to replace libjpeg9-dev with libjpeg62-turbo-dev
Thanks, Tim! This article has a good bit of dust on it, and I imagine these changes are due to later library updates / raspberry pi 4 versions and such. I’ll bench test this and update the article accordingly as I have time. Glad it worked out for you!