Webcam streaming, time-lapse and motion detection

I have a webcam connected to my server, and I want to use it to offer a stream I can access using my phone, and also to perform some time-lapse capturing as well as motion detection when I’m not at home with email notification.

Previously I had tried zoneminder, but I didn’t really like the approach. This time I’m using a great package just called “motion.” I didn’t think it would be full-featured, but it is great. Installation is simple:

sudo apt-get install motion

Then I edited the /etc/default/motion, setting start_motion_daemon=yes.
The last setup file to edit is /etc/motion/motion.conf. It is very well documented and has so many options. Here are some of the tweaks I made:

v4l2_palette 2 #mjpeg palette
width 1280 #capture resolution
height 720 #capture resolution
text_double on #easier to read time/date
snapshot interval 4
target_dir /tmp/motion #stores snapshots/motion videos in RAM using tmp dir
snapshot_filename timelapse/%Y%m%d_%H%M%S #subdirectory for snapshots
webcam_port 39820 #changed to random port

This gave a webcam stream visible using a web browser, and captures a snapshot every 4 seconds for time-lapse. This is all stored in the tmp RAM disk in order to not be constantly writing to the hard drives more than needed. So that I don’t lose the snapshots upon reboot, I use the following file in /etc/init.d/transientmotion based on my /var/log RAM disk script of /etc/init.d/transientlog.

# Provides: transientmotion
# X-Start-Before:	motion
# X-Stop-After:		motion
# X-Interactive:	yes
# Required-Start:	
# Required-Stop:	
# Default-Start:	2 3 4 5
# Default-Stop:		0 1 6
# Short-Description:	Keeps RAM timelapse photos between reboots
# Description: Moves the contents of /tmp/motion/ to disk upon
#              shutdown/reboot, and restores upon startup.

# Version 1.0
# Inspired by transientlog.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.

DESC="Transient motion directory"

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME

# Load the VERBOSE setting and other rcS variables
. /lib/init/

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions

if [ -z "$VARLOGPERM" ]; then
	log=`basename $VARLOG`
	unset var log

	# Return
	#   0 if transient motion has been started
	#   1 if transient motion was already running
	#   2 if transient motion could not be started

	[ -f $LOCKFILE ] && return 1
	# Check if I'm root
	[ `id -u` -eq 0 ] || return 2

	# If VARLOG does not exist?
	[ -d $VARLOG ] || return 2

	# VARLOGPERM either does not exist (first invocation)
	# or is empty (left from previous invocation).
	[ -d $VARLOGPERM ] || mkdir -p $VARLOGPERM || return 2
	[ -d $VARLOG ] || mkdir -p $VARLOG || return 2

	# Mount a tmpfs over VARLOG.
	# The mount will shadow the current contents of VARLOG.
	# So, before, make a bind mount so that looking into VARLOGPERM
	# we'll see the current contents of VARLOG, which
	# will not be available anymore as soon as we mount
	# a tmpfs over it.
	if [ $? -eq 0 ]; then
		# Populate the tmpfs
		if cp -rfp $VARLOGPERM -T $VARLOG; then
			# Success!
			touch $LOCKFILE
			return 0

		# Something went wrong...

		# Rollback the mount

	# Rollback the directory mangling
	return 2

do_stop() {
	# Return
	#   0 if daemon has been stopped
	#   1 if daemon was already stopped
	#   2 if daemon could not be stopped
	#   other if a failure occurred

	#[ -f $LOCKFILE ] || return 1

	# Check if I am root
	[ `id -u` -eq 0 ] || return 2

	# Merge back to permanent storage

	# The following cannot fail... or can it?
	rm -f $LOCKFILE
	return 0

do_reload() {
	# Return
	#   0 if transient log has been reloaded
	#   1 if transient log was not running
	#   2 if transient log could not be reloaded

	#[ -f $LOCKFILE ] || return 1
	# Check if I am root
	[ `id -u` -eq 0 ] || return 2

	# Merge back to permanent storage
	touch $LOCKFILE
	return 0

case "$1" in
	[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
	case "$?" in
		0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
		2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
	[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
	case "$?" in
		0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
		2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
  	if [ -f $LOCKFILE ]; then
		echo "$DESC is running"
		echo "$DESC is stopped"
		exit 1
	log_daemon_msg "Reloading $DESC" "$NAME"
	log_end_msg $?
	echo "Usage: $0 {start|stop|status|reload}" >&2
	exit 3

Then I checked the start up priority of motion

sudo find /etc/rc*.d -iname ???motion

I set my new script to 1 lower (using a higher number) than it, so that it will start and stop after.

sudo update-rc.d transientmotion defaults 61

Additionally, I want to transcode my snapshots into x264 mp4 video on a schedule. The following script does that, making the video and then deleting the snapshots upon finishing. I set this to cron at 11pm and 6am (the hours between 11pm and 6am are usually just darkness).

if [[ $EUID -ne 0 ]]; then
   echo "This script must be run as root" 1>&2
   exit 1
DATER=`date +%Y-%m-%d_%H%M%S`
mencoder "mf://$FOLDERTMP/*.jpg" -fps 60 -ofps 60 -of lavf -ovc x264 -x264encopts preset=veryslow:crf=24:threads=auto -o $FOLDEROUT/$DATER.mp4
if [ "${RC}" -ne "0" ]; then
    # Handle the error.
    echo "error"
    # Everything was ok.
    echo "no error"
    rm -r $FOLDERTMP

This stores the resulting file outside of the /tmp, archiving it.

I’ll add information about turning on/off motion detection and emailing images/movies at some point, but not now.

Leave a Reply

Your email address will not be published. Required fields are marked *