I decided to create a time-lapse screen recorder as a side project. Mostly for fun, but also to see how I spend my work days.
I got the original idea from Nick Winter in this youtube video. He worked a 120-hour work week as a personal challenge, and no doubt posted the video as an inspiration for others to do the same or something similar. Me being me, however, I was more interested in the technology.
At first, I tried to find programs that already exist. The one he used (which he wrote) only works on Mac. I use linux. It was a pretty simple program, so I didn't think it would be that hard (or take that long) to reproduce. The plan was pretty straightforward: write a script to take screenshots periodically, then stitch them together into a video.
For taking screenshots, I used scrot. (Worst name for anything ever, in my opinion.) It has an excellent command line interface (perfect for automation), it offers several useful options, it can save with a custom filename or a timestamp, and it can execute a command of your choice afterward. So I created ten-line bash script to execute scrot every 10 seconds.
#!/bin/bash cd /home/brwong/recorder interv=10 echo "HELLO!!" echo "today is " $(date) echo "now recording ($interv) ..." while true do scrot -z -e './resizer.sh $f $w $h' sleep $interv done
This will capture a screenshot, execute the resizer script on it (see below), sleep for the interval (10 seconds), and repeat. It will run until I kill the program. With a bit more complexity, I could add an interactive interface, or convert it into a background service.
The resizing script uses the
convert program from imagemagick to shrink the three-monitors-wide screenshot down to a standard HD video size, fill the rest of the image in black, and add a timestamp in the bottom corner. It's unfortunate for the video that my wide monitors setup is much wider than it is tall. If I were clever, I could break up the three separate screens and place one of them on top or underneath, but that might be a little disorienting; and it would take a lot more work. Also, if I wanted to, I could have used another program (such as ffmpeg) to snap a photo from the laptop's webcam and include a shot of me in the video.
#!/bin/bash filename=$1 #givenwidth=$2 #givenheight=$3 convert $filename -resize 1920x -gravity North -background black -extent 1920x800 $filename convert $filename -gravity SouthEast -pointsize 48 -fill red -annotate +100+0 $(date +"%H:%M") $filename mv $filename snaps/$filename
When interpreting the program's arguments, keep in mind that this script is executed by
scrot in the recorder script. The
givenheight were included because I was still trying to figure out how exactly the sizing worked. I left them in to hint that both
convert have those options available.
After a day of work (or any length of time), I go to the terminal that was running the recorder script, kill it, then execute the compiler script. I'm a programmer, so I called it
compiler.sh. I don't know what the actual video editing term is for converting a series of images into a video.
I used mencoder for the task. The bash script first makes a list of all the images, and writes the list to a file. Because of the timestamp image filenames, they're already in the correct order. Then it calls
mencoder on that file, passing in the formats of the input images and desired output video, and specifying that there is no sound. Mencoder makes the video and puts it in the destination folder. Then, just for my convenience, the script uses
xclip to copy the path of the new video file to the clipboard, so I can open it afterwards. Normally, I delete the image files manually, in case something goes wrong with the compilation, but this could be included in the script as well.
#!/bin/bash videoname=$(date +"%Y%m%d-%H%M%S").avi rm -f files.txt for i in snaps/* do echo $i >> files.txt done echo "mencoder -nosound -ovc lavc -lavcopts vcodec=mpeg4 -o vids/$videoname -mf type=png:fps=20:w=5760:h=1200 mf://@files.txt" mencoder -nosound -ovc lavc -lavcopts vcodec=mpeg4 -o vids/$videoname -mf type=png:fps=20 mf://@files.txt rm -f files.txt echo -n "$videoname" | xclip -selection clipboard -in echo "wrote video file to $videoname"
A careful reader will discover that I used a for-loop to write the list of images in the "snaps" folder to a file, instead of simply writing the results of
ls snaps directly to a file. I'm hoping there was a valid, non-embarrassing reason for that, but it's entirely possible that there isn't.
And that's it! Three scripts that could really be one script, a bunch of easily automated yet not automated steps, and, ultimately, the functionality that I wanted. The end result was pretty cool, and I learned a few things along the way.