Raspberry Pi Webcam Over the Internet Using MJPG-Streamer

View your Raspberry Pi Webcam from anywhere. Connect to it from a unique domain name and check in on your house or pets while you are away.
Requirements For This Walkthrough
Materials
- Local network
- Mac or PC
- Raspberry Pi camera module, a Compatible Webcam (or the exact same one I used to write this tutorial)
- Raspberry Pi running Raspbian “wheezy”
- Domain name
- Router capable of supporting DynDNS, noip, or other dynamic DNS service; or a software-based dynamic DNS client (not covered in this walkthrough)
- lighttpd Web server running on the Pi (optional–allows your to embed a stream to a Webpage, which can be password-protected)
- HDMI Cable (*optional)
- Keyboard (*optional)
- Mouse (*optional)
- Monitor with HDMI input (*optional)
- *If the Raspberry Pi is set up as a headless machine, you will not need a monitor, keyboard, or mouse–just another computer, which would be used to access it remotely over the network via SSH.
Downloads
- MJPG-Streamer
- input_uvc_patch.txt
Resources
- http://blog.miguelgrinberg.com/post/how-to-build-and-run-mjpg-streamer-on-the-raspberry-pi
- http://www.instructables.com/id/Create-an-internet-controlled-robot-using-Livebots/step5/Get-the-webcam-streamer-for-Raspberry-Pi/
- http://wolfpaulus.com/jounal/embedded/raspberrypi_webcam/
- http://www.linuxcircle.com/2013/02/06/faster-video-streaming-on-raspberry-media-server-with-mjpg-streamer/
- http://skillfulness.blogspot.com/2010/03/mjpg-streamer-documentation.html
- http://www.plugcomputer.org/plugforum/index.php?topic=6231.0
- http://iomem.com/index.php?archives/3-Starting-out-with-Lighttpd.html&serendipity%5Bentrypage%5D=4&serendipity%5Bentrypage%5D=all&serendipity%5Bentrypage%5D=all
- http://nutz95.wordpress.com/2013/05/14/raspberry-pi-pirider-install-mjpegstreamer/
- http://www.phillips321.co.uk/2012/11/05/raspberrypi-webcam-mjpg-stream-cctv/
Step-by-step Walkthrough
Short-and-sweet Version (for advanced users)
lsusb
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install libjpeg8-dev imagemagick libv4l-dev
sudo ln -s /usr/include/linux/videodev2.h /usr/include/linux/videodev.h
sudo apt-get install subversion
cd ~
svn co https://svn.code.sf.net/p/mjpg-streamer/code/mjpg-streamer/ mjpg-streamer
cd mjpg-streamer
make mjpg_streamer input_file.so input_uvc.so output_http.so
sudo cp mjpg_streamer /usr/local/bin
sudo cp output_http.so input_file.so input_uvc.so /usr/local/lib/
sudo cp -R www /usr/local/www
sudo vi ~/.bashrc
export LD_LIBRARY_PATH=/usr/local/lib/
source ~/.bashrc
/usr/local/bin/mjpg_streamer -i "input_file.so -f /tmp/stream -n pic.jpg"-o "output_http.so -w /usr/local/www"
sudo vi /usr/sbin/livestream.sh
#!/bin/bash
/usr/local/bin/mjpg_streamer -i "/usr/local/lib/input_uvc.so" -o "/usr/local/lib/output_http.so -w /var/www/stream -c username:password"
sudo chmod 755 /etc/init.d/livestream.sh
sudo update-rc.d livestream.sh defaults
Conceptual Overview
- Update the Raspberry Pi and install software dependencies
- Download the MJPG-Streamer source code
- Compile the source code
- Install the patch to prevent a blank white screen
- Capture images from the Webcam and serve them on a Webpage
- Set MJPG-Streamer to run at boot
Two Methods: Camera Module or USB Webcam
You can use the Raspberry Pi camera module, or any compatible USB Webcam. I found that that the USB Webcam method is easier and better quality, but there are instructions for both. In the walkthrough, I’ll be using a USB Webcam. The camera module instructions can be found in the appendix.
Step-by-step Walkthrough
Check If the Pi Recognizes the Webcam
Plug in the USB Webcam and run the command:
lsusb
Look for an entry relating to your Webcam. This is a good indicator it has been recognized.

Update Pi and Install Dependencies
First, update the Raspberry Pi and then install some of the dependencies of MJPG-Streamer.
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install libjpeg8-dev imagemagick libv4l-dev
An adjustment needs to be made: the videodev.h
file has been replaced with videodev2.h
but this change needs to be made manually. To do this, just create a symbolic link.
sudo ln -s /usr/include/linux/videodev2.h /usr/include/linux/videodev.h
Download and Compile MJPG-Streamer
Unfortunately, MJPG-Streamer isn’t available via apt-get , so we need to compile it from source. This may be more complex than setting up a Webcam using Motion, but I found MJPG-Streamer to be less resource-intensive so the additional complexity of setting it up is worth it.
There are a few different ways to install MJPG-Streamer. The easiest is via subversion, which is what I will walkthrough. If you want directions for some other methods, look in the appendix at the bottom of the post.
Download via Subversion (svn)
Install subversion (if necessary).
sudo apt-get install subversion
Then, download a copy of the MJPG-Streamer source code to your home folder and move into the directory when the download is complete:
cd ~ svn co https://svn.code.sf.net/p/mjpg-streamer/code/mjpg-streamer/ mjpg-streamer
cd mjpg-streamer
There are a lot of plugins included with MJPG-Stream, but for this walkthrough, we will just compile three. If you only plan to use a USB Webcam, you can modify the command below to suit your needs. Just leave off the items you do not want.
- input_uvc.so (for USB Webcams) : copies JPGs from a single input (the Webcam in this case) to one or more output plugins. This is good for streaming larger images at a higher framerate with lower CPU usage.
- input_file.so (for camera module): similar to the above, but copies them from a directory.
- output_http.so: streams the files to a Webserver
make mjpg_streamer input_file.so input_uvc.so output_http.so
Alternatively, running make , you can compile everything that comes with MJPG-Streamer. I chose to just install what was necessary to save on storage space and resources.
Copy MJPG-Streamer to an Alternate Location
You could run MJPG-Streamer right from the folder after it is compiled ( ./mjpg_streamer
), but it might be better to give it a permanent home.
Run the following commands to copy it to a more globally-accessible area:
sudo cp mjpg_streamer /usr/local/bin
sudo cp output_http.so input_file.so input_uvc.so /usr/local/lib/
sudo cp -R www /usr/local/www
/usr/local/
is a common place for third-party items or things added to a system by an admin. But you could put them wherever you like, or just leave it where it is. You will just need to modify the paths for the rest of the walkthrough.
Export Paths
If you did try to run mjpg_streamer
now, it probably returned an error about search paths. This is because right now, the system doesn’t know where to find the files. This is an easy fix. Just append the following line to ~/.bashrc
(assuming you ran the commands above to copy the files to /usr/local/
. This will make it a permanent change so that you don’t need to do this every time you log in:
export LD_LIBRARY_PATH=/usr/local/lib/
Now you can either log out and back in again, but it is easier to run the source command to apply the change (this has the same effect as logging in):
source ~/.bashrc
Now, you can simply call mjpg_streamer
no matter what directory you are in. We are almost ready to start capturing images. But if you run into a blank white screen, you’ll want to install the patch below (see also user experiences in the comments section)
Install A Patch
Many users reported a blank white screen when trying to use it. Apparently, this patch fixes it (see also here).
vim mjpg-streamer-code/mjpg-streamer
vim input_uvc_patch.txt
Paste in this code and save the file
--- plugins/input_uvc/input_uvc.c (revision 174)
+++ plugins/input_uvc/input_uvc.c (working copy)
@@ -405,9 +405,13 @@
if(pcontext->videoIn->formatIn == V4L2_PIX_FMT_YUYV) {
DBG("compressing frame from input: %d\n", (int)pcontext->id);
pglobal->in[pcontext->id].size = compress_yuyv_to_jpeg(pcontext->videoIn, pglobal->in[pcontext->id].buf, pcontext->videoIn->framesizeIn, gquality);
+ /* copy this frame's timestamp to user space */
+ pglobal->in[pcontext->id].timestamp = pcontext->videoIn->buf.timestamp;
} else {
DBG("copying frame from input: %d\n", (int)pcontext->id);
- pglobal->in[pcontext->id].size = memcpy_picture(pglobal->in[pcontext->id].buf, pcontext->videoIn->tmpbuffer, pcontext->videoIn->buf.bytesused);
+ pglobal->in[pcontext->id].size = memcpy_picture(pglobal->in[pcontext->id].buf, pcontext->videoIn->tmpbuffer, pcontext->videoIn->tmpbytesused);
+ /* copy this frame's timestamp to user space */
+ pglobal->in[pcontext->id].timestamp = pcontext->videoIn->tmptimestamp;
}
#if 0
@@ -418,8 +422,6 @@
prev_size = global->size;
#endif
- /* copy this frame's timestamp to user space */
- pglobal->in[pcontext->id].timestamp = pcontext->videoIn->buf.timestamp;
/* signal fresh_frame */
pthread_cond_broadcast(&pglobal->in[pcontext->id].db_update);
Index: plugins/input_uvc/v4l2uvc.c
===================================================================
--- plugins/input_uvc/v4l2uvc.c (revision 174)
+++ plugins/input_uvc/v4l2uvc.c (working copy)
@@ -450,6 +450,8 @@
*/
memcpy(vd->tmpbuffer, vd->mem[vd->buf.index], vd->buf.bytesused);
+ vd->tmpbytesused = vd->buf.bytesused;
+ vd->tmptimestamp = vd->buf.timestamp;
if(debug)
fprintf(stderr, "bytes in used %d \n", vd->buf.bytesused);
Index: plugins/input_uvc/v4l2uvc.h
===================================================================
--- plugins/input_uvc/v4l2uvc.h (revision 174)
+++ plugins/input_uvc/v4l2uvc.h (working copy)
@@ -28,6 +28,7 @@
#include <stdio.h>
+#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
@@ -105,6 +106,8 @@
int framecount;
int recordstart;
int recordtime;
+ uint32_t tmpbytesused;
+ struct timeval tmptimestamp;
};
/* context of each camera thread */
Then run these commands to apply the patch
patch -p0 < input_uvc_patch.txt
sudo make USE_LIBV4L2=true clean all
sudo make DESTDIR=/usr/local install
Using input_uvc.so to Capture Images
Start running mjpg_streamer
with the command:
/usr/local/bin/mjpg_streamer -i "/usr/local/lib/input_uvc.so" -o "/usr/local/lib/output_http.so -w /usr/local/www"
This command options are as follows:
-i
: uses input_uvc.so (the USB Webcam) as input-o
: output_http.so for the output (sending the images to a Web server-w
: the directory, which has the HTML, CSS, and JS files: /usr/local/www
You can cancel the stream by pressing Ctrl+C. If you want to experiment with some other options, some are listed below:
-b
: runs in the background-p
: set a default port instead of the default 8080-c
: prompts for username:password-y YUYV
: enables YUYV format and disables MJPEG mode-f
: framerate (in seconds)
If you used the -b option, you will get your prompt back. So how do you stop it from running? After running the command, you will see a line like:
forked to background (4979)
If you want to stop the stream, just run:
kill 4979
which just kills the process ID (PID) of MJPG-Streamer.
View the Webcam Live-stream From a Browser
(while connected to your local network)
Even if you have already set up a Webserver, you can still run this without problem because it is accessed on a different (default) port: 8080 . So when you navigate to it in a browser, just append :8080 after the IP address:
- locally: http://localhost:8080
- from another device on the network: http://<raspberry_pi’s_ip_address>:8080

Accessing Your Pi Over the Internet
Viewing your Webcam while connected to your local network is cool, but I’ll show you how to access your Webcam from anywhere by going to a URL such as: myDomain.com:8080 . This stream can be password-protected, but it really isn’t very secure, so be careful if you make this available online.

Pre-requisites
- Forward port 8080 to your Raspberry Pi
- Enable a dynamic DNS service on your router
- (optional) Setup a lighttpd Web server with a password-protected directory
Once the steps above are complete, you will be able to access your Webcam stream from any browser by navigating to http://myDomainName.org:8080 . But there is no password yet! Anyone on the Internet will be able to see your Webcam.
We can tell MJPG-Streamer to use a password with the -c option. This password is not very secure (it is only base 64 encoded), but it can offer a first line of defense. Someone could easily sniff and decode the password, but if you are on a trusted network then it is not as much of a problem.
The command would look like this:
/usr/local/bin/mjpg_streamer -i "/usr/local/lib/input_uvc.so" -o "/usr/local/lib/output_http.so -w /usr/local/www -c username:password"
The best way to secure any online resource is with a layered-defense model. So before you would want this out on the Internet, you might want to be protected using other tools.
Embed the Stream into a Web Page
For simplicity, just make the page in the same directory that is serving up the HTML files ( /usr/local/www/
in this walkthrough). This makes it easier to make sure the page works. After you know it's working, you can move it somewhere else, but you will just need to adjust the paths. Enter the following HTML code (adjusting to your setup) and it is ready to go.
<html>
<head><title>Kitty-cam Live-stream</title></head>
<body>
<center><h1>Meow</h1></center>
<center>
<img src="/?action=stream" />
</center>
<body>
</html>
If you want, you can also use lighttpd to password-protect your embedded-stream.
Now, just navigate to your page to see it:
- http://192.168.1.100:8080/catcam.html (on the local network)
- http://myDomainName.org:8080/catcam.html (over the Internet)
Run MJPG-Streamer as a Daemon (Background Service)
Until now, we have just been launching MJPG-Streamer on an as-needed basis by running a command with our options. If you want to make this more permanent and have the Raspberry Pi start the Webcam stream when it boots up, we need to tell it to do so.
There are two scripts below: a very basic one that just runs the command, and an advanced script that will allow you to use the service command to control it:
sudo service livestream.sh start
sudo service livestream.sh stop
sudo service livestream.sh restart
Simple Script
A very simple script to do this is below:
sudo vi /etc/init.d/livestream.sh
#!/bin/bash
/usr/local/bin/mjpg_streamer -i "/usr/local/lib/input_uvc.so" -o "/usr/local/lib/output_http.so -w /usr/local/www -c username:password"
Save the script. Make it executable:
sudo chmod 755 /usr/sbin/livestream.sh
This next command makes sure it is executed during boot:
sudo update-rc.d livestream.sh defaults
Advanced Script
Below is a script that should load MJPG-Streamer at boot and allow use of the service command:
#!/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 "/usr/local/lib/input_uvc.so" -o "/usr/local/lib/output_http.so -w /usr/local/www -c username:password"
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 "/usr/local/lib/input_uvc.so" -o "/usr/local/lib/output_http.so -w /usr/local/www -c username:password"
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
Once saved, run the same commands as above:
sudo chmod 755 /etc/init.d/livestream.sh sudo update-rc.d livestream.sh defaults
Success!
Now your Webcam is available over the Internet and starts up when you turn on your Raspberry Pi.
Appendix:
Download MJPG-Streamer via curl or wget
wget http://sourceforge.net/code-snapshots/svn/m/mj/mjpg-streamer/code/mjpg-streamer-code-182.zip unzip mjpg-streamer-code-182.zip
Finish running the commands from the Via subversion section.
Download MJPG-Streamer via scp
Download MJPG-Streamer on another device and then use scp to copy it over to the Raspberry Pi.
scp ~/Downloads/ pi@192.168.1.100:~/
Finish running the commands from the Via subversion section.
Using input_file.so to Capture Images
For this method, you need to set the camera to start recording images using the command raspistill
. You will also need a folder to store the files in; for now, just make it in /tmp
:
mkdir /tmp/stream
Then, enable the camera with a command similar to the following:
raspistill --nopreview -w 640 -h 480 -q 5 -o /tmp/stream/pic.jpg -tl 100 -t 9999999 -th 0:0:0 &
The options of the command are explained below, so adjust them as you see fit:
–nopreview
: Do not display a preview window-w and -h
: image with and height (in pixels)-q
: quality <1-100>-o
: write out to a file (named pic.jpg)-tl
: time (in ms) before it takes a picture and shuts down and link latest complete image to filename-t
: time (9999999ms)-th
: set thumbnail parameters (x:y:quality)&
: sends the job to the background (not part ofraspistill
)