Video Streaming using Raspberry Pi 3 and USB Webcam

After building our Birds Feeder we quickly realized that it is quite useless without having realtime video steaming from the feeder to be able to observe birds and to see the food falling into the feeder when sending a remote command.

Of course we wanted to make the streaming possible with (nearly) zero budget. We had Raspberry Pi 3 and an old Logitech webcam available and that looked enough to build a video streaming device.

Birds Feeder Live Stream

We were looking into different online streaming services like YouTube, Vimeo and Ustream. Neither of them worked for us for mainly for three reasons:

All of them require stream to be encoded in H264 format. This is great format for video streaming and is the current industry standard, however cheap USB webcams do not support hardware encoding in H264 and Raspberry Pi does not have enough performance to make encoding in real time.

All web streaming services have a huge lag (about half minute) which makes them useless for control applications where you want to observe immediate reaction of the system to control events.

Some of the services require end user to watch quite annoying and long video ads before they can actually connect to the stream

So the decision was to build our own streaming using available components. Below diagram illustrates the whole set up.

The idea is to have Raspberry Pi capture the video from a webcam and stream it via HTTP in MJPG (motion Jpeg) format natively supported by most USB webcams. Though, exposing Raspberry to Internet and serve to many end users is not a good idea for both performance and security reasons, so we decided that a remote server should consume single video stream from raspberry over HTTP and re-distribute it to the end users.

Setting up video streaming with Raspberry Pi and a USB webcam

After many failed attempts to get mjpg stream working it turned out to be very straightforward with the mjpg-streamer utility.

First of all, check that your webcam supports mjpg format and what resolutions and frame rates are supported.

Shell

1

2

3

4

5

6

7

8

9

10

11

pi@raspberry:~$v4l2-ctl--list-formats

ioctl:VIDIOC_ENUM_FMT

Index:0

Type:Video Capture

Pixel Format:'YUYV'

Name:YUV4:2:2(YUYV)

Index:1

Type:Video Capture

Pixel Format:'MJPG'(compressed)

Name:MJPEG

The first is raw video, which will also work but you will need to load you Raspberry CPU with software conversion to mjpeg. The second format is mjpg and is exactly what we need.

To list all supported frame rates and resolutions run

1

v4l2-ctl--list-formats-ext

Then get the source of mjpg-streamer and compile it.

Prerequisites for succesful build

Shell

1

2

3

sudo apt-getinstall libjpeg-dev

sudo apt-getinstall cmake

After you have prerequisites on your system from your home directory run

Shell

1

2

3

4

5

6

7

git clonehttps://github.com/jacksonliam/mjpg-streamer

cdmjpg-streamer/mjpg-streamer-experimental/

make

sudo makeinstall

At this point you should be able to start the streaming server on Raspberry

This will reload systemd configuration and you will be able to use the following commands to control your service

Shell

1

2

3

sudo systemctl enable webstream.service

sudo systemctl start webstream.service

sudo systemctl status webstream.service

This should be enough if you only plan to access your stream from a local network. However if you plan to expose your stream to Internet and handle more users simultaneously, you can proceed to the next step.

Re-distributing live video stream via Linux Server

We have a dedicated server running Linux connected to a fast broadband connection. The server runs nginx. The idea is to install mjpg-streamer on the Linux server which will source the video stream from Raspberry in a single stream and redistribute it to as many user as it can handle. Also, we realize that although mjpg-streamer is great in streaming it might be not the best in terms of security, so we decided to not allow end users to access mjpeg-streamer directly but rather configure nginx upstream, so end user sends their requests to nginx, where you configure your access rules and authorization and nginx forwards http requests to mjpg-streamer.

First, compile mjpg-streamer on your Linux box, the same way you did it with Raspberry.

If you run your Linux box and raspberry on different network, make sure you allow inbound tcp connection on port 9090 to the network hosting your Raspberry and to forward incoming traffic on port 9090 to your Pi.

At this point you should be able to navigate to http://yourlinuxbox:9090 and see the same picture as you see when accessing your raspberry. The only difference is that your Linux box handles multiple users while your raspberry has only single stream to your Linux box.

This is not the end. Make sure you disable access from outside to your Linux box on port 9090 so end users will not be able to access mjpg streamer directly.

After this you can configure your nginx to upstream all requests to a certain url to mjpg-streamer.

In the configuration file of your web site add the following

1

2

3

upstream video {

server 127.0.0.1:9090;

}

and inside the server{} configuration

1

2

3

location /video/ {

proxy_pass http://video/;

}

Note the trailing slashes, they are important.

Restart nginx.

Now when you can navigate to http://yournginxurl/video and see the broadcast. Embedding the live stream to a page would be as simple as adding an <img> tag.

Of course you will also want to run mjpg-streamer on startup, just repeat the steps you have done for Raspberry with adjusting the content of /etc/systemd/system/webstream.service to contain proper command line.