The one where windows are recorded

I make little game jam games a few times a year. Any one who makes games know screenshots and solid gifs are essential tools of the trade.

I’ve been using scrot to capture screenshots for some time but wanted an easy way to capture video / gifs during game development.

Before I switched to awesome I was using peek, which worked fine. Peek does not behave well with awesome.

Beyond being a paint to use with awesome, peek had a couple quality of life issues.

  1. no easy way to capture the contents of a window without /very/ carefully placing the capture regions
  2. sometimes you’d capture the perfect gif but peek would crash out before processing the gif.

Enter ffmpeg and xwininfo

xwininfo lets you pull the x info out of a window, and ffmpeg, using x11grab, can record the contents of just that window.

Running it from your shell is as easy as:

ffmpeg -y -f x11grab -framerate 30 -window_id $(xwininfo | grep 'xwininfo: Window id' | awk '{print $4}') -i :0.0 ~/Pictures/Screenshots/RECORD-$(date +%Y-%m-%d_%H-%M_%S).mp4

To stop the recording you can either kill the specific ffmpeg PID, or use pkill and kill all running instances of ffmpeg.

pkill ffmpeg

The recording will be spit out in an mp4 format that you can review before deciding to make it into a gif.

I use gifski for my gif generation (it can be installed from cargo) and the following script. You can hand roll your own for your own needs.

cargo install gifski
FILE=$(echo $1 | sed 's/\.mp4//g')
T=$(mktemp -d -t RECORD-XXXX)
ffmpeg -i $FILE.mp4 $T/frame%04d.png
gifski --width 320 -o $FILE.gif $T/frame*.png
rm -rf $T

Note, gifski can do mp4 -> gif conversion directly, but relies on libavutil-dev.

Alternatively, you could also just bash it all together into a single command, as I’ve done in the awful.key example setup below.

    awful.key({ modkey, "Shift"}, "r",
       function ()
          if (recording)
          then
             recording=false
             awful.util.spawn_with_shell("pkill ffmpeg")
          else
             recording=true
             awful.util.spawn_with_shell("sleep 0.5 && \
    T=$(date +%Y-%m-%d_%H-%M_%S) && \
    FILE=~/Pictures/Screenshots/RECORD-$T && \
    ffmpeg -y -f x11grab -framerate 30 -window_id $(xwininfo | grep 'xwininfo: Window id' | awk '{print $4}') -i :0.0 $FILE.mp4 && \
    mkdir /tmp/$T/ && \
    ffmpeg -i $FILE.mp4 /tmp/$T/frame%04d.png && \
    gifski --width 320 -o $FILE.gif /tmp/$T/frame*.png && \
    rm -rf /tmp/$T")
          end
       end,
       {description = "record window", group = "applications"}),

Thats it!

Now you can press “Modkey Shift r” to start a recording, click on the window you want to record and then press “Modkey Shift r” again to stop the recording.

If there are any issues with the mp4 -> gif conversion you have the mp4 file to fall back on / reconvert manually.

You could always drop the xwininfo command if you want to capture your whole screen or pass in the x window id of your currently active window if you’d rather not have to use your mouse at all.

The code provided in this tutorial can be used under the MIT Licence