Setting Up a Video Surveillance System with Free Software and Linux
Part I. Dialup

Walter Eastes

This page reports what I did to set up a video surveillance system using inexpensive cameras, an inexpensive video capture card, and an old computer. What I wanted was a system that would run day and night for months, capturing images from a couple of cameras whenever there was something happening, and that one could inspect from a computer far away. The main problem in accomplishing it, and what makes it interesting really, is that there are so many pieces that must work together and so many choices for each part. Thus there are many ways to do it, but this is what I did.

This first part deals with setting up a system that can be dialed up by telephone from a remote location to view the surveillance images. The second part shows what I did later to serve the images over the internet at much higher speeds.

Computer and Operating System

The computer, named toad4, is an old 400 MHz Intel Pentium running Slackware 11.0 with the 2.6.17.13 Linux kernel. It has two 30 GB hard drives, one mounted as / and the other as /ext or "extra" that is dedicated to the surveillance images.

The camera is a Swann SW214-OCD indoor/outdoor color and infrared LED camera that comes with a 100 foot cable. The cable has both composite video and electrical power. The power can be supplied either at the camera end or at the computer end by plugging it into a transformer brick that plugs into an electrical outlet.

The camera connects to a PV-143 four port video capture card from Bluecherry. The video card has BNC connectors and I had to get composite to BNC connectors for it.

Automatic Startup after Power Failure

Although it is not the first thing one thinks about, it is critical for an unattended computer to restart and resume video capture after the electricity goes off and comes back on. Most PC-style computers today have a momentary contact power switch that must be pushed again after the electricity is restored to start the computer. We need to defeat this feature so that it starts when power is applied. Sometimes it is a BIOS option, but on this machine with a Microstar International MS-6119 ATX BX2 motherboard, one removes jumper JP1 on the motherboard.

With this change, it boots, checks the disks, and goes to the login prompt right after it is plugged in. Now all we need is to start the required services automatically, by putting statements at the end of the /etc/rc.d/rc.local script. These are described further on.

Getting the Camera to Work

That the camera works was verified by plugging it into the composite video port of a (U.S.) television. It also works when plugged into the composite video port of a Hauppauge WinTV-PRV-250 PCI tuner card on another computer, where it was operated with the excellent ivtv driver from www.ivtvdriver.org or dl.ivtvdriver.org. There one sets input 1, the composite video input jack with

The NTSC format is the default. Now all you have to do is to produce an mpeg video. In fact you can do to watch the camera image with a couple of seconds delay. However, the motion video capture software will not work with ivtv and the video capture card operated with the bttv driver does not work this way.

The video capture card has one identifiable chip labeled

Clearly it is a Brooktree 878 compatible device that can work on one port at a time, which is all I need. The card is detected upon bootup and lspci shows (The backslash \ at the end of a line indicates that it was continued onto the following line.) Doing results in this output from /var/log/messages: The duplicate symbol errors come about because i2c and some other things are compiled into this particular kernel, and are not modules that modprobe tries to load. It causes no problem, however. Here is the partial lsmod output: Therefore, this line was entered at the end of /etc/rc.d/rc.local.

Both the motion and the Zoneminder documentation suggest getting the camera to work with something like xawtv to determine the right parameters. Thus xawtv-3.95 was downloaded from bytesex.org/xawtv, compiled and installed. Whereas xawtv with the -hwscan option works fine, starting xawtv gives these messages and quits:

No amount of messing with v4l-conf or trying to enable DGA or load v4l in xorg.conf resulted in anything that worked. In fact I locked up the kernel hard as a brick a couple of times. It looks as if the graphics card is not going to display xawtv. It doesn't work with xine either.

However, we don't need all of that. One can take a snapshot from the card with this sequence:

This also works: Furthermore, doing and plugging the camera into the second port works too. So now we know how to configure the motion software.

The 720x480 size was used here because that appears what the cameras will do, although there is a black border on two sides of the images that is a different size on different cameras. The Bluecherry web site says that the PV-143 can go as big as 640x480 NTSC, but we may be exceeding that here.

By the way, it took a lot of trial and error before I was able to get an image from the camera. At first, all I could get with either streamer or with motion was a blue screen, suggesting that no camera was connected to the capture card. Then I discovered that the video composite connector was very loose on the jack. All I had to do was bend the three ground tabs a bit inward to get good contact and right away got an image.

As another aside, here is a script that allows you to view the output of the camera more or less continuously:

It snaps images as fast as it will go and uses ImageMagick to display them on the screen with a one-second update. But don't do this while motion is running (see the next section) or things will get really confused.

Motion Configuration

The package motion-3.2.10.1 was downloaded from www.lavrsen.dk/twiki/bin/view/motion/WebHome, compiled and installed. It is virtually certain that Zoneminder from www.zoneminder.com would work too, but motion appeared to be a lot smaller and simpler.

Since I have only one camera for now, all configuration was taken care of in the file /usr/local/etc/motion.conf, which contained these statements that were changed from the file as distributed:

This file configures motion to take one snapshot every minute even if nothing is happening and save it in a directory under /ext/motion labeled with the four digit year, two digit month, and two digit day with the file name made up of the two digit hour (0 to 23), two digit minute, two digit second, and "-snap.jpg". When motion is detected, two images are captured per second and stored in the same directory with the same file name but ending in "-NN.jpg", where NN is a two digit sequence number.

The program is started simply with "motion" (really /usr/local/bin/motion as I installed it) and operates in the background. That statement goes into /etc/rc.d/rc.local too.

Web Server Configuration

Now we have motion running continuously capturing images, and we need a convenient way to inspect them. Certainly one can cd to a given date in the /etc/motion directory and view the jpeg files with xv or something. But a better way would be to make them available to a web browser.

The Apache web server is installed but not started by default in this Slackware distribution. However, all that is needed is

to make it start at bootup, and to start it now. One can do to reread its configuration file and begin again.

The configuration file is /etc/apache/httpd.conf and these are the lines that were changed from what was distributed:

With just one user, me, it did not seem reasonable to start five servers as in the distributed configuration file.

When one requests the web page http://localhost, one gets the file /var/www/htdocs/index.html, which I changed to this:

This index page retains the Apache manual, since it is handy to have it available, but adds a series of cgi scripts in perl. It is clear that the web pages for the motion images must be dynamically generated, since there is no way to write an html page knowing what images will be available in the future. If all else fails, the "Motion directory" entry gives access directly to the /etc/motion directory. To make the motion image directory available to the web pages, a link was made:

The dynamic web pages are generated at several levels. At the top level, the "Earlier" link generates a table of all available years and months with this perl code:

At the next level is the makemonth.pl script that is called with the four digit year and two digit month. The words "this" and "last" can be used also to work out this and last month at the time it is called. As can be seen in the following code, the real work is done by the cal program, the output of which is captured and formatted as an html table. Clicking on one of the days in this calendar executes makeday.pl with the selected year, month, and day.

Before printing each calendar entry, we check to see if the directory for that day exists with the "if ( -d ..." statement. If so, then it becomes a link to the next level program to display the images for that day. If not, then it is just printed as text.

Suceedingly lower levels of cgi scripts display the hours of the selected day showing how many snapshots and motion images are there. Eventually, one can select individual images to view directly in the browser, since they are just jpeg files.

Login by Serial Line

We want to dial up toad4, the computer that is running motion and look at the images with a web browser that accesses the web server configured as described in the last section. In order to try out the setup without driving all the way to a remote computer, I set up another, even older computer, a 200 MHz Pentium called toad2, and connected it to toad4 with a serial null modem cable. The cable runs from /dev/ttyS0 on toad2 to /dev/ttyS0 on toad4.

The first thing to do is to enable login to toad4 on ttyS0, which is done by locating this line in /etc/inittab and changing it to

The -r option indicates it is not a modem but a direct connection. The -s speed option is needed since the mgetty default is 38400. The command "telinit q" rereads the /etc/inittab file so that the changes take effect.

The getty installed on this Slackware distribution is getty_ps, which works for this serial line. But, as outlined in the next section, it failed to do dialup the way we need. Thus I downloaded mgetty-1.1.36 from mgetty.greenie.net, compiled and installed it. For use on a serial line, I needed to add the lines

in /usr/local/etc/mgetty+sendfax/mgetty.config. By the way, the progress of mgetty can be watched by

Now starting "minicom -s" on toad2 allows one to backspace over all the modem initialization strings so that no initialization is done on ttyS0. Likewise, the speed needs to be set to 115200 to match what mgetty was told on toad4. One must not forget to save the settings, which go into the default file /etc/minirc.dfl. Then starting minicom with no arguments results in a login prompt and we can log in as some user. Note that root login is denied in /etc/securetty, as it does not list ttyS0.

The next step is to start the point to point protocol with pppd on both toad4 and toad2 so that we can run a web browser on toad2 and get web pages from the Apache server on toad4.

Configuration of pppd on toad4 is done with two files in /etc/ppp. General options for both serial and dialup are in /etc/ppp/options and are these:

We are not doing any authorization (noauth) or login with pppd since it was already done with mgetty. Options specially for the serial port ttyS0 on toad4 are in /etc/ppp/options.ttyS0 which contains It specifies the IP addresses to assign to the local and remote machine as symbolic names, which are defined as dotted quads in the /etc/hosts file which contains These are IP addresses reserved for local networks and not exposed to the internet. In addition, we set the alias to make it easy to start pppd on toad4. Not to forget, we need to make pppd executable by any user with

Now on toad2, we need /etc/ppp/options to have

We might as well make an alias on toad2 also: where we have already linked /dev/ttyS0 to /dev/serial. Why not put the corresponding IP address into /etc/hosts on toad2:

Now back to toad2 where we are logged into toad4 as some user through minicom. Just do "ppp" to start pppd on toad4. Nothing further will happen on toad2, but on toad4, /var/log/messages will note the startup of pppd. Then on toad2, leave minicom running and start another xterm. Here issue the "ppp" command to toad2. That will start pppd on toad2, which will register the local and remote IP addresses that we specified to pppd on toad4. We can leave this xterm just sitting there.

Now we can open yet another xterm and start up a browser with http://toad4 and get the index.html page configured on toad4 and view the motion images.

To stop pppd, go back to the xterm on which it was started on toad2 and kill it with Ctrl-C. We can do this because of the -detach option in the toad2 /etc/ppp/options file. Without it, it would run in the background and we could look up its process id with

and stop it with the kill command. A termination message will appear here on toad2 and also in /var/log/messages on toad4. Then you can go back to the minicom instance where the prompt has now returned and continue to work on toad4 through toad2. One logs off toad4 as usual, Ctrl-D will do it.

Login by Modem

The modem on toad4 is /dev/ttyS1, which linked to /dev/modem. Everything done with the serial line applies to the modem with the added issues of dialin and security.

The dialin issue is that the phone line is also used for ordinary voice calls in and out and has an answering machine set to answer after four rings. We want to use this line to dial up toad4 on top of all of that, and to do it from a remote location, of course. The standard way to handle all of this is to use the ringback feature, not to be confused with call back, which is something else again. With ringback, you dial the number, let it ring a couple of times, but not long enough to trigger the answering machine, then hang up. Then within a short time, 30 seconds in this case, you dial again, and mgetty answers it on the first ring this time.

This ringback protocol neatly takes care of several situations. First of all, anyone calling is going to get the answering machine if they ring four times and there will be no other call in 30 seconds while they are leaving a message. If they give up before four rings, then they are not likely to try again within 30 seconds. Furthermore, if someone answers the phone in a couple of rings, then they can talk to the caller. But anyway, if I am dialing up toad4 to view the motion images, it is because no one is home to answer the telephone, right? Persistent telemarketers might ring twice in 30 seconds, but then they would get the high-pitched connection tone, which is just what they deserve.

The already installed getty_ps-2.1.1 is supposed to support ringback, but I had trouble with it. Not only did it ignore the -R ringback option, but it failed to respond to the INIT string. A look at the source code revealed that ringback was compiled out by default, but I gave up because of the other problem and installed mgetty. What mgetty is doing can be watched by running

especially interesting while the phone is ringing.

The security issue is that we do not really want just anybody dialing up these motion images. Since toad4 and toad2 are not accessible to anyone but me, I do not have passwords on any of the accounts, not even on root. We are going to need something to protect dialup, but I do not feel like putting passwords on all the accounts, not even on root.

(By the way, setting no password is not quite straight forward. The trick is to set a password of anything at all, even an empty string, with adduser, for example. Then edit /etc/shadow and delete all the characters in the password field, the second one. Then you can log into the account and will not be asked for a password.)

A nice solution is to create a new user called "ppp", say, on toad4 with the same shell as any other ordinary user but supply a robust password just for this account. Then add this line to /etc/login.access on toad4:

Now the only way to login to toad4 on the modem line is as user ppp, for which a password is required. After successful login as ppp, then one can su - to another user, even to root without a further password. Thus there is no restriction on what a dialin user can do as long as they can authorize themselves with the ppp password.

With these two issues resolved, we can configure toad4 for remote dialin. We need this line in /etc/inittab:

and "telinit q" to restart it. The -R 30 option sets ringback with no more than 30 seconds delay between calls. Next, we need the following pppd options for the modem in /etc/ppp/options.ttyS1: It differs from options.ttyS0 in that gives a different IP address to the remote machine, a modem is specified, at a slower speed. Now toad4 is ready for remote dialin.

The configuration of the remote machine is similar to that of the toad2 serial line except that it is a modem. The default minicom configuration is usually correct if the modem is linked to /dev/modem. The default speed in minicom is 38400 just like that for mgetty, so we go with it. It is easy to dial in manually with minicom on the remote machine with

for example. After a couple of rings, it may be interrupted by pressing the Enter key. Then issue the dial command again. A connect message and login prompt follows.

After successful login as user ppp on toad4, one can issue "ppp" to start pppd on toad4. One does not need to specify the line here, as it appears to use the login line by default. But then, when one starts pppd on the remote machine from another xterm,

is needed.

From here on, it is the same as for the toad2 serial line.

Automating Remote Dialup

It is handy to automate the process of dialing up toad4 with ringback from a remote location and then starting pppd. This remote machine is also used to dial up an ISP for internet access, but I want to dial up toad4 to browse the video surveillance images too. The pppd program with a chat script can do both.

There is one script to dial up the ISP and another to dial up toad4. The one to dial toad4 is called "toad4" and contains just this:

The options common to dialing the ISP and toad4 are in /etc/ppp/options and are these:

For both purposes, either the ISP or toad4 will supply the IP addresses, thus noipdefault. In additon, the same modem is used, linked to /dev/modem.

The options specially for toad4 are in /etc/ppp/peers/toad4.options and are these:

The advantage of putting these options in a call statement, which means they need to be in the directory /etc/ppp/peers, is that they can be priviledged options like noauth but can be done by an ordinary user. Of course, pppd needs to be setuid root as before. This trick comes straight from the examples in the man page for pppd.

The chat script in /etc/ppp/toad4.chat needs to trigger ringback on toad4. The following slick method is given in the web page carnot.pathology.ubc.ca/DebianPage.html, apparently written by Peter Easthope at the University of British Columbia:

The first atdt dial command uses a few commas to delay after dialing while it connects and rings a couple of times, then just hangs it up (h0). In the next line, the series of \d characters delay for long enough for the toad4 modem to discover that the line is dead and to reset and wait for the ringback. Then the next atdt dial command rings it back, ignores the CONNECT reply and gives the user name ppp (the only one that is allowed) and password. Following that, it waits on the command prompt "$ " and starts pppd on toad4. The instance of pppd that is now running on this remote machine starts the ppp protocol and signs on with the local and remote IP addresses as usual.

Now I just start up a web browser on the web address http://toad4, assuming that

is in /etc/hosts here too.

Adding More Cameras

Two more cameras were procured, but these were a different kind, QSee QS60F. The main difference is that they have somewhat stronger infrared capability and can see a bit farther in the dark than the first camera.

Motion has a roundrobin feature that is meant for handling this situation with a multiple input video capture card that can handle only one camera at a time. The configuration options common to all cameras go in /usr/local/etc/motion.conf, which now has these statements that differ from the distributed file:

The main change is to invoke thread files at the end. I also needed to set roundrobin_skip 2 from the default 1. Without that modification, there were a lot of "composite" images taken, that is, images that had parts of one camera image and parts of another. Apparently, motion was switching inputs and grabbing an image while the last capture was in progress. Of course, such composite images were detected as motion and saved as motion images. After the number of frames to skip was bumped up to 2, composite images rarely were seen again. By the way, increasing roundrobin_frames did not help anything, and turning on switchfilter pretty much ignored all motion.

The thread files mentioned in motion.conf are motion-xxx.conf, where xxx is some description of the camera location. Here is one of them:

This thread file is for the camera plugged into the third input, numbered input 2, starting at 0. It puts the camera designation "Back" in the lower left corner of the images, names the snapshot images

and the motion images Now both the image file names and the images themselves are identified as to the camera, which is useful.

Deleting Image Files

With three cameras running all the time, things can get out of hand. For example, when one finds a few thousand images on the back camera between 3 and 4 pm one day that are nothing but bright sunlight speckled through wind blown tree branches, it is handy to delete them to keep from gobbling up disk space. One could try logging in and doing

to delete just the motion images. But that often yields too many arguments for the bash shell to handle. This would work: but it is getting really inconvenient to type it right. You really want to be able to delete a range of specific images right from the web browser where you were viewing them.

It is easy to put a link to this script on appropriate pages:

The above perl code generates a table of numbers of snapshots and motion images for each camera at each hour of the selected day. Clicking on a number in a column deletes all of those images, because it is a link to rmglob with the file names specified in the same glob notation that did not always work in the rm command shown above.

The rmglob program is written in C and compiled so that it can be setuid to the owner of the motion images and thus has the permission to delete them. The glob routine in the C library makes rmglob.c really simple:

By default, the Apachee web server runs the cgi programs as user nobody, whereas motion is started by /etc/rc.d/rc.local as user root, although it does not need to be. One solution might be to run motion as nobody also so that the motion images could be deleted by scripts run by Apachee. That should work, but I prefer rmglob to deal with whatever motion gives it. Thus rmglob.c is compiled to rmglob and then

Under some circumstances, having rmglob setuid root would be a major security disaster as it allows any user to delete any or even all files on the system. But on this particular system running the surveillance cameras, any user can do "su -" and be running as root anyway. So rmglob gives nothing that they did not have already. Note that dial-in users need to give the ppp password first before they can do any of this.

Future Enhancements

A number of improvements suggest themselves. For one, the presence of a high speed internet connection brings up new possibilities, some simplifications and some complications. That is described in Part II of these pages. They are added to from time to time.

This page was last updated in September, 2009.

This document is

Best viewed with any browser