Webcam streaming with ffmpeg

I’m a bit of a stressed person, and when I’m not home, I like to have a webcam streaming what’s going on, mainly to see how my dog is doing. At my main house, I use the fabulous motion project, which has a ton of cool features like recording images and videos when there’s movement, playing a sound, handling many cameras and so on.

As I said before, I acquired an apartment destined for rental, and it has really poor Internet access, as it is located on the mountainside, only weak ADSL was possible to get.
Another point, I own a MacBook Pro for music purposes, and when I come crash here, this is the computer I take with me so I can compose if inspiration comes ;) So when I get out the apartment, this will be the machine streaming what’s happening in the house.

First thing, while motion builds on the Mac, it does not find -or at least I didn’t find how- any webcam device. They are exposed via avfoundation and motion doesn’t seem to handle that framework.
After struggling a bit with the incredibly over-complicated vlc command line, I fell back to ffmpeg which package is available through pkgin.

Here I found a gist with a working example, except I had to considerably lower the parameters in order to meet the low bandwidth needs. Here’s a working, low consuming bandwidth example of an ffserver configuration:

HTTPPort 8090
HTTPBindAddress 0.0.0.0
MaxHTTPConnections 10
MaxClients 10
MaxBandWidth 1000
CustomLog -

<Feed camera.ffm>
File /tmp/camera.ffm
FileMaxSize 5000K
</Feed>

<Stream camera.mpg>
Feed camera.ffm
Format mpjpeg
VideoFrameRate 2
VideoIntraOnly
VideoSize 352x288
NoAudio
Strict -1
</Stream>

Start the server using ffserver -f ffserver.conf.

In order to stream the webcam to this server, here’s the command I use:

$ ffmpeg -f avfoundation -framerate 5 -video_size cif -i "0" http://localhost:8090/camera.ffm

Now, the stream is visible at http://192.168.4.12:8090. The command line would be very similar under GNU/Linux except you’d use -f video4linux2 and -i /dev/video0.

Obviously, the goal here is to watch the stream when I’m not home, with my mobile phone web browser.
As I mentioned in my previous post, I use a wrt54g router running dd-wrt which is connected to an OpenVPN hub I can reach from my network. dd-wrt actually has a NAT section, but unfortunately, it only maps internal IPs to the public interface, not taking into account any other type of network.
Nevertheless, it is possible to add very custom iptables rules using the Administration → Commands → Save firewall button. So I added the following rule:

# redirects tunnel interface (tun1), port 8090 (ffmpeg) to the Macbook
iptables -t nat -A PREROUTING -i tun1 -p tcp --dport 8090 -j DNAT --to-destination 192.168.4.12

Ensuring the Macbook has a static DHCP address.

Of course you probably don’t want this window into your house wide opened to the public and will want to hide it behind an nginx reverse proxy asking for authentication:

location /webcam2/ {
    auth_basic "Who are you?";
    auth_basic_user_file /usr/pkg/etc/nginx/htpasswd;
    proxy_pass http://10.0.1.20:8090/; # OpenVPN peer address
    proxy_redirect off;
    proxy_set_header X-Forwarded-For $remote_addr;
}

And voila! A poor man’s video surveillance system in place ;)