Bash: How to record your screen using FFmpeg on Linux Arch?

I've left my year-long companion elementary os and changed to XeroLinux for my main machine. This was mostly due to being annoyed by the underlying Debian base and constant fighting to use not-so-outdated packages and having to use insecure sources a lot. It just didn't feel right anymore.

On elementary, I've used a lot of utility tools for various tasks, for example, for recording screencasts. Under the hood, these utils use shell commands such as FFmpeg. Unfortunately, these utils came with their own challenges and often didn't get updated enough. I ended up with a strong desire to go organic and run the FFmpeg commands directly. After all, I'm a developer and passionate Linux user, not a Window(s)-User ;) With the switch to XeroLinux it was time to also change this.

Here is how I use FFmpeg to record screens from bash for my daily work. My go-to solution is the built-in FFmpeg.

Record your Screen using FFmpeg on the CLI #

First, determine the screen size and position: To record the screen, you need to know the size and position of the screen. You can determine this by using the xdpyinfo command in the terminal:

xdpyinfo | grep dimensions

For me, it prints:

  dimensions:    2880x1800 pixels (762x476 millimeters)

Here 2880x1800 is my configured screen resolution.

Second, use the following command in the terminal to start recording the screen:

ffmpeg -f x11grab -s <screen-size> -i :0.0+<screen-position> -r 25 /tmp/output.mp4

Replace <screen-size> with the size of your screen, here "2880x1800". The <screen-position> with the position of your screen, for example, "0,0". The -r option sets the frame rate to 25 frames per second, and /tmp/output.mp4 is the name of the output file written.

When you are finished with your recording press Ctrl+C in the terminal. FFmpeg will complete the file and write it to the disk.

How to record a specific window using FFmpeg? #

The above command will record the entire screen. If you want to record only a specific window, you can use the xwininfo command to determine the position and size of the window, and use it in the -i option instead of the screen position.

As a One-Liner #

These steps are a little unhandy in daily life. You can also merge the output xdpyinfo into a single FFmpeg command using grep and awk:

ffmpeg -f x11grab -video_size $(xdpyinfo | grep 'dimensions:' | awk '{print $2;}') -i :0.0 -c:v libx264 -preset ultrafast output.mp4

This command records the entire screen, without audio. It uses xdpyinfo to get the screen dimensions and sets them as the -video_size option using a sub-shell ($(....)).

The video codec used is libx264 with the ultrafast preset. Again, the output file is named /tmp/output.mp4.

As a One-Liner, with Audio #

ffmpeg -f x11grab -video_size $(xdpyinfo | grep 'dimensions:' | awk '{print $2;}') -i :0.0 -f alsa -i default -c:v libx264 -preset ultrafast -c:a aac -b:a 128k /tmp/output.mp4

This command records the entire screen and audio from the default ALSA device. It uses xdpyinfo to get the screen dimensions and sets them as the -video_size option. The -f alsa -i default options capture audio from the default ALSA device.

The video codec used is again libx264 and the audio codec used is aac with a bitrate of 128k. Of course, you can modify the options as needed.

Going Lossless #

If you aren't into losing any detail, you can go useless by setting the video codec to FFV1. FFmpeg supports several lossless video codecs, such as FFV1, HuffYUV, and Ut Video. Using FFV1 you can run:

ffmpeg -f x11grab -video_size $(xdpyinfo | grep 'dimensions:' | awk '{print $2;}') -i :0.0 -c:v ffv1 -level 3 -g 1 -coder 1 -context 0 /tmp/output.mkv

In this command, the -c:v ffv1 option sets the video codec to FFV1, which is one of FFmpeg's lossless video codecs. The -level 3 option specifies the compression level, with higher levels resulting in better compression but requiring more processing power. The -g 1 option sets the GOP (group of pictures) size to 1, which means each frame is a keyframe and ensures that each frame is independently decodable. This is actually making it lossless. The flags -coder 1 and -context 0 appear to be also required for lossless encoding.

The output file is named /tmp/output.mkv in this case. It's a container format that supports lossless video and other codecs.

Note: lossless video recording can result in very large file sizes and require high disk write speeds.

More? You can check the Arch documentation if you are keen to learn more about screencasts or find alternative tools.


Since you've made it this far, sharing this article on your favorite social media network would be highly appreciated 💖! For feedback, please ping me on Twitter.