Timelapse screen recording of separate X displays

Update 2014-04-8: See this post on how to deal with two monitors on a single X screen.

This post is for those with separate X displays, who want to do timelapse screencapture. There are many utilities for doing this kind of timelapses, in particular, I'd recommend chronolapse, which does a very good job, even with multiple monitors. If that works for you, then go for it! However, if you have trouble with it working for separate X-displays as I did, or just want more control, read on!

The post is broken up into small steps, which are put together as a complete script.
There is also a demo video made using this script at the very bottom.

1. Capturing screenshot of full X display

There are several ways to take a screenshot from the command line. The two most interesting utilities are xwd, and Image Magick's import utility, as these utilities are available in most systems by default (and if you don't have the latter, you should).

Since using import caused jittering when capturing the screen, I'll stick with xwd. Here is how to take a screenshot: xwd -root -out screenshot.xwd

2. Specifying which X to use

The environment variable DISPLAY determines which display is used. By setting this variable prior to executing a command, you determine which display it communicates with. Try out these examples in a terminal: DISPLAY=:0.0 gedit
DISPLAY=:0.1 gedit

Putting it together with the xwd utility, you can specify which display to take a screenshot of: DISPLAY=:0.0 xwd -root -out screenshot-left.xwd
DISPLAY=:0.1 xwd -root -out screenshot-right.xwd

3. Creating the thumbnail

Since the goal was to have a picture-in-picture of one monitor shown on top of the other, we will have to create this thumbnail. This is where the ImageMagick utilities shine. First let's grab a screenshot: xwd -root -out screen.xwd Then, lets create reduce the image, so that it fits a 300x300 pixel box, while retaining its aspect ratio. convert screen.xwd -thumbnail 300x300 thumbnail-300px.png


Now, lets add a 2-pixel border, with the color #881111aa.

convert screen.xwd -thumbnail 300x300 \
   -bordercolor "#881111aa" -border 2 thumbnail-border-300px.png

Let's add a nice falloff shadow, on a white background (so you can see it).

convert screen.xwd -thumbnail 300x300 \
   -bordercolor "#881111aa" -border 2 \
   \( +clone -background black -shadow 100x3+2+2 \) \
       +swap -background white -layers merge +repage \
       thumbnail-border-shadow-whitebg-300px.png

And of course, we want a transparent background, so for the sake of completeness:

convert screen.xwd -thumbnail 300x300 \
   -bordercolor "#881111aa" -border 2 \
   \( +clone -background black -shadow 100x3+2+2 \) \
       +swap -background none -layers merge +repage \
       thumbnail-border-shadow-nobg-300px.png

4. Overlaying images.

Again, ImageMagick comes to the rescue.
Here is how to place thumnail.png on top of image-large.png at position (100,20).

convert -composite image-large.png thumbnail.png \
   -geometry +100+20 imageoverlay.png

5. Executing a command every X seconds

To execute a command every X seconds, you might think that watch -n X ./foo or perhaps while sleep X; do ./foo ; done would do a good job. And you would be right, assuming that./foo executes immediately. When it's a command you want to execute repeatedly, at fixed intervals, you have to send the command to the background, using&.

This will exceute the script ./foo.sh once every second, even if foo.sh takes several seconds to complete.

6. Final script

Putting together the various pieces mentioned so far, this is the final script.

7. Bonus - rendering video

A 30 fps video, consuming 15 frames for each second in the output, can be made using ffmpeg with the following:

While I wrote this post, I had the above script running, and this is the produced video: