Make a screencast with ffmpeg

Several applications to record your desktop exist, but ffmpeg can do it all by itself, via its x11grab format specifier. But there were some challenges:

Performance

What ffmpeg does when recording your screen is to transcode the X11 video into compressed output, based on file extension. But I wanted to record a game, and this proved to be too resource-intensive in combination, esp. if I want ffmpeg to produce high quality output. So I recorded the session in raw, uncompressed format. Be aware, your hard drive will fill up really quickly (and a slow hard drive might incur another performance penalty): a 5 minute 1152x864px video has 7.5GB.

In the end I changed the screen resolution of the whole desktop, started the game in fullscreen mode and told ffmpeg to record that:

$ sleep 5 ; ffmpeg -f alsa -i hw:0 -f x11grab -r 25 -s 1152x864 -i :0.0 -c:v ffvhuff -c:a flac output1.mkv

Since MKV is a container format, it can also contain uncompressed video formats.

Sound

If you use pulseaudio or jack audio, other solutions apply. But with plain ALSA it isn't so easy to simply record what the computer sends to your speakers. In the end I just plugged the cable that goes from Line Out (usually to my speakers) back into Line In. Then (via alsamixer, press F4 to get capture channels) I had to activate the main CAPTURE channel and set the Input Source to Line. Surprisingly, this did not result in feedback. I had to fiddle with the volumes to avoid distortion and background hum. It's not HiFi, but good enough.

alsamixer capture

Edit and Reduce Size

But I had recorded two separate scenes, which now had to be slightly trimmed and concatenated.

Trim first - example:

$ ffmpeg -i output2.mkv -t 00:02:36 -acodec copy -vcodec copy output2-a.mkv

It starts at zero by default (if not, use the -ss option) and uses the first 2min 36s.

Next one needs to create a text file (let's call it list.txt) with a list of files to be concatenated:

file 'output1-a.mkv'
file 'output2-a.mkv'

and then concatenate like this:

$ ffmpeg -f concat -safe 0 -i list.txt -c copy output-full.mkv

Lastly, I make a high quality two-pass encoding of the resulting file. Please note that, although I chose the MKV format again, this is a totally different codec with much smaller file size. I also must first concatenate the videos into their final form, and then transcode.

$ ffmpeg -i output-full.mkv -an -vcodec libx264 -pass 1 -preset veryslow -threads 0 -b 1000k -x264opts frameref=15:fast_pskip=0 -f rawvideo -y /dev/null

$ ffmpeg -i output-full.mkv -acodec aac -ab 64k -vcodec libx264 -pass 2 -preset veryslow -threads 0 -b 1000k -x264opts frameref=15:fast_pskip=0 output-final.mkv

Note that the sound is only transcoded during the second pass (to 64kb AAC).

The uncompressed 7.5GB file (~5 minutes) has shrunken to a very reasonable 38.8MB at 1000kb/s while keeping the original resolution of 1152x864px. The quality is very good, I can't spot any difference to the original:

Click to view video Click to view video