2014년 11월 5일 수요일

Time-lapse recording of meditation sessions with motion, ffmpeg, and bash script

Background

I have been doing insight meditation for the past several months, but have a problem with being consistent and disciplined enough to actually meditate when I feel tired or too busy. I have used Beeminder (here are my automatically tracked goals) to good effect to keep me on track for certain goals that can be automatically monitored, i.e. RescueTime, Fitbit step count, Dual N-Back practice sessions, number of cards reviewed in Mnemosyne (similar to Anki but easier to use), etc.

For more free-form goals that require human oversight, StickK is a good tool. Both Beeminder and StickK are commitment devices that help people actually stick to their goals by making them put money on the line; if you go off track (determined by a human referee in the case of StickK, and by a computer in the case of Beeminder), your credit card gets charged some amount (that exponentially increases in Beeminder).

I track weekly pushups and meditation sessions using StickK. In the case of pushups, I prop up my smartphone so that it will record me doing one set of X pushups. The video is automatically uploaded to G+ from where I share a link to the video with my StickK referee. For 25 pushups, the videos are usually about 60 seconds long. But this will not work for meditation, considering the fact that a meditation session can last anywhere from 10 to 30 minutes. The battery life on many smartphones is pretty terrible, and even if you could take a half-hour video of yourself sitting on a mat meditating, who the hell would watch it? I want to save my StickK referee from such torture as well as save memory card space and battery life on my smartphone. Solution: use Linux!

The Tools

motion

motion is a web-cam utility that begins taking snapshots when motion is detected in front of the camera. It is included in the package repositories of many Linux distros, and I use the version from the Archlinux community repository. motion is commonly used in DIY CCTV projects using the Raspberry Pi, however, I will use it to take time-lapse photos of my meditation sessions. By default, motion will start taking pictures whenever it senses motion, but we need to change this default behavior so that it will take a photo every N seconds. To do this, you need to edit /etc/motion/motion.conf as follows:

First make sure that motion daemon mode is turned off

############################################################
# Daemon
############################################################

# Start in daemon (background) mode and release terminal (default: off)
daemon off

Although the comment above claims the default is off, in Archlinux the default is actually on.

############################################################
# Snapshots (Traditional Periodic Webcam File Output)
############################################################

# Make automated snapshot every N seconds (default: 0 = disabled)
snapshot_interval n
In our case, we set n to 6.

Since we will be taking time-lapse photos, we need to turn off the feature that takes pictures when motion is detected:

############################################################
# Image File Output
############################################################

# Output 'normal' pictures when motion is detected (default: on)
...
# Can be used as preview shot for the corresponding movie.
output_normal off

After installing the motion package in Archlinux, you also have to edit the permissions on /var/run/motion so that it is writable by the regular user. Something like the following should do the trick:

sudo chown username:username /var/run/motion

If your /usr/local directory is not already writable by the regular user, you will also need to recursively change the permissions on this directory as well because motion outputs all its image files to the path /usr/local/apache2/htdocs/cam1 (at least this is true on Archlinux). You can recursively change ownership of directories and subdirectories using the -R option in chown.

There are several other config changes you might want to make to /etc/motion/motion.conf.

If you don't want motion to create partial preview videos every X frames as well as a final video (I think it's a waste of space), you need to edit the following section:

# Use ffmpeg to encode mpeg movies in realtime (default: off)
ffmpeg_cap_new off


ffmpeg

Once you have finished taking time-lapse photos in motion, all the images will be contained in /usr/local/apache2/htdocs/cam1

Now you need to use ffmpeg to render these time-lapse images into a video (without audio). In our video, we want each image to be shown for 1 second each and the video should be 25 frames per second. We can render such a video as follows:

ffmpeg -framerate 1/1 -pattern_type glob -i "*.jpg" -r 25 filename.mp4

Note: -framerate flag ensures that each input image appears for 1 second (to make each image appear for n seconds, set this flag to 1/n)

When using the -i flag (input), if you wish to use wildcards (to render all jpg files in a directory, for example) you need to preface the -i with the -pattern_type flag glob option

The -r flag sets the frame rate for the output video file.


bash script

You don't want to have to remember the ffmpeg invocation above every time you want to record a time-lapse video. Below is a script I made to launch motion, render the images, and then cleanup the output directory once video rendering is complete:





My original script didn't have any error trapping before running rm *.jpg and I bitterly came to regret this when one day ffmpeg exited with an error; despite no .mp4 video being rendered, my silly script deleted all jpg files. The unsafe lines were as follows:
...
ffmpeg -framerate 1/1 -pattern_type glob -i "*.jpg" -r 25 $DATE.mp4
rm *.jpg

The problem with these lines is that even if ffmpeg exits with an error, the script will not stop; the rm command will still be executed! After learning my lesson the hard way, I read up on error handling from William Shotts' wonderful bash tutorial. I also highly recommend his book, The Linux Command Line.