Homemade Screen Recorder

personal tech choice work

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.

Recorder

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.

Resizer

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 givenwidth and givenheight were included because I was still trying to figure out how exactly the sizing worked. I left them in to hint that both scrot and convert have those options available.

Compiler

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.

Ever Unfinished

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.


Add a comment

Previous Post Next Post