How to make screencasts with FFmpeg
FFmpeg is able to use audio and video streams from many different sources. In order to record a screencast, you can use the x11grab input module for recording an X screen and the alsa input module for audio recording.
In this article I will explain how to use the x11grab and the alsa input module to record a screencast as mp4 file with h264 video and aac audio. You need to have FFmpeg compiled with --enable-x11grab
and --enable-libx264
to achieve this, so run $ ffmpeg
to check the compile configuration of your FFmpeg version.
When I started to write this article I spent a lot of time to figure out a way to record everything that comes out of my laptop’s soundcard. I ended up with creating an alsa loopback device and a new .asoundrc to route all output devices to the loopback device so I could record everything I hear.
First, create the alsa loopback device:
$ sudo modprobe snd_aloop
To load the module on boot, create /etc/modules-load.d/AlsaLoopbackDevice.conf and add snd_aloop
The loopback device gets its own alsa device ID and might get an ID lower than the one of your soundcard. This caused some troubles with my web browsers. I was not able to hear anything from a web page. The solution was to restore the original ID of my soundcard. You don’t need a udev rule for this, it can be achieved by adding some options to the snd_* kernel modules.
Create /etc/modprobe.d/sound.conf and add
options snd_hda_intel index=0
options snd_aloop index=1
The name of the kernel module for your soundcard might be different depending on the vendor.
The next step is to configure the loopback device such that it records everything that is also going to the speakers or line out. This part is taken from the Arch Linux Forums.
Create ~/.asoundrc and add
pcm.!default { type asym playback.pcm "LoopAndReal" #capture.pcm "looprec" capture.pcm "hw:0,0" } pcm.looprec { type hw card "Loopback" device 1 subdevice 0 } pcm.LoopAndReal { type plug slave.pcm mdev route_policy "duplicate" } pcm.mdev { type multi slaves.a.pcm pcm.MixReale slaves.a.channels 2 slaves.b.pcm pcm.MixLoopback slaves.b.channels 2 bindings.0.slave a bindings.0.channel 0 bindings.1.slave a bindings.1.channel 1 bindings.2.slave b bindings.2.channel 0 bindings.3.slave b bindings.3.channel 1 } pcm.MixReale { type dmix ipc_key 1024 slave { pcm "hw:0,0" rate 48000 #rate 44100 periods 128 period_time 0 period_size 1024 # must be power of 2 buffer_size 8192 } } pcm.MixLoopback { type dmix ipc_key 1025 slave { pcm "hw:Loopback,0,0" rate 48000 #rate 44100 periods 128 period_time 0 period_size 1024 # must be power of 2 buffer_size 8192 } }
You don’t have to reboot or log out and back in for the changes to take effect. Alsa parses the .asoundrc every time a sound device is opened.
Now we need to find out the display ID from the X-Server and the loopback device ID from Alsa. Run $ arecord -l
to find the ID of the loopback device and $ xrandr
to get the screen ID and your actual screen resolution. Let’s assume your screen ID is 0, the resolution is set to 1600×900 and the ID of your loopback device is hw:1,1. To record a screencast with h264 video and aac audio in good quality you can try
$ ffmpeg -y -f x11grab -draw_mouse 1 -framerate 25 -video_size 1600x900 -i :0.0 -f alsa -i hw:1,1 -c:v libx264 -pix_fmt yuv420p -b:v 2500k -c:a aac -strict -2 -b:a 192k -movflags +faststart testgrab.mp4
The option -draw_mouse tells FFmpeg whether to render the cursor into the video (1) or not (0), and -framerate is pretty much self-explanatory. -video_size sets the size of the recorded video. This should be the native resolution of the screen you are recording. It does not make any sense to set a higher resolution, because FFmpeg would only scale up the video, which results in quality loss. The input ID is of the form display.screen, where display is usually 0 (your local X-Server display) and screen can be found using $ xrandr
. The Alsa device ID can be found using $ arecord -l
and is of the form card:device. The option -pix_fmt is needed, because the x11grab input module records video as raw RGB, which is incompatible with most players and playback devices when using h264 codec. The pixel format has to be converted to yuv420p. If you open your recorded screencast with VLC and the video is just a green screen, then you forgot to add this option. If you want your videos to have highest compatibility with target devices (older iOS versions or all Android devices), use -profile:v baseline and -level 3.0 options and values. This disables some advanced features but provides for better compatibility. If you want to increase the video quality, you can set a higher value for -b:v, but for simple video content like text, presentation frames and so on, 2500k should be sufficient. The aac encoding in FFmpeg is still experimental, so you need the -strict -2 option and value to override the “don’t use experimental codecs” setting in FFmpeg. You can add -movflags +faststart as an output option if your videos are going to be viewed in a browser. This will move some information to the beginning of your file and allow the video to begin playing before it is completely downloaded.
You can add more sophisticated x264 encoding options with the x264opts option. Multiple x264 options are combined with a “:” and follow the form key=value, i.e. -x264opts keyint=123:min-keyint=20. More x264 encoding options can be found on MeWiki
Posted on January 19, 2014, in Audio / Video, Command-Line and tagged aac, alsa, evilshit, ffmpeg, h264, Linux M0nk3ys, Linux Monkeys, linuxmonkeys, screencast, x11grab, x264, yuv420p. Bookmark the permalink. 5 Comments.
Two words: try “simplescreenrecorder”.
SimpleScreenRecorder is a nice and handy tool and I know there are several others out there for making screen recordings. I have used VLC for this for some time, like funkym0nk3y did for his post about how to set up a stateful firewall with iptables. The idea behind my post was to find a working solution for FFmpeg, to note down some FFmpeg options and links for further reference and to configure an alsa device for loopback recording with the intention that it might also be helpful for others.
VLC is nice but it does not record the mouse and you have to use a program called “extramaus” in order to record it. Dunno why this happens only in GNU/Linux. In older vlc versions I could use a .png file and the mouse was shown but in the newer versions even the .png file with the mouse pointer does not record the mouse anymore. Here’s my favourite cli vlc recording option:
cvlc screen:// :screen-fps=30 :sout=’#transcode{vcodec=h264,acodec=mpga,ab=128,channels=2,samplerate=44100}:file{dst=/home/frost/Desktop/video-record-1.mp4}’
Hello. Used your command but it records without audio(internal). Here is some output:
r@prime:~$ ffmpeg -y -f x11grab -draw_mouse 1 -framerate 25 -video_size 1440×900 -i :0.0 -f alsa -i hw:0,0 -c:v libx264 -pix_fmt yuv420p -b:v 2500k -c:a aac -strict -2 -b:a 192k -movflags +faststart testgrab.mp4
ffmpeg version 3.2.10-1~deb9u1 Copyright (c) 2000-2018 the FFmpeg developers
built with gcc 6.3.0 (Debian 6.3.0-18) 20170516
configuration: –prefix=/usr –extra-version=’1~deb9u1′ –toolchain=hardened –libdir=/usr/lib/x86_64-linux-gnu –incdir=/usr/include/x86_64-linux-gnu –enable-gpl –disable-stripping –enable-avresample –enable-avisynth –enable-gnutls –enable-ladspa –enable-libass –enable-libbluray –enable-libbs2b –enable-libcaca –enable-libcdio –enable-libebur128 –enable-libflite –enable-libfontconfig –enable-libfreetype –enable-libfribidi –enable-libgme –enable-libgsm –enable-libmp3lame –enable-libopenjpeg –enable-libopenmpt –enable-libopus –enable-libpulse –enable-librubberband –enable-libshine –enable-libsnappy –enable-libsoxr –enable-libspeex –enable-libssh –enable-libtheora –enable-libtwolame –enable-libvorbis –enable-libvpx –enable-libwavpack –enable-libwebp –enable-libx265 –enable-libxvid –enable-libzmq –enable-libzvbi –enable-omx –enable-openal –enable-opengl –enable-sdl2 –enable-libdc1394 –enable-libiec61883 –enable-chromaprint –enable-frei0r –enable-libopencv –enable-libx264 –enable-shared
libavutil 55. 34.101 / 55. 34.101
libavcodec 57. 64.101 / 57. 64.101
libavformat 57. 56.101 / 57. 56.101
libavdevice 57. 1.100 / 57. 1.100
libavfilter 6. 65.100 / 6. 65.100
libavresample 3. 1. 0 / 3. 1. 0
libswscale 4. 2.100 / 4. 2.100
libswresample 2. 3.100 / 2. 3.100
libpostproc 54. 1.100 / 54. 1.100
[x11grab @ 0x5569dff3be20] Stream #0: not enough frames to estimate rate; consider increasing probesize
Input #0, x11grab, from ‚:0.0‘:
Duration: N/A, start: 1528115857.680928, bitrate: N/A
Stream #0:0: Video: rawvideo (BGR[0] / 0x524742), bgr0, 1440×900, 25 fps, 1000k tbr, 1000k tbn, 1000k tbc
Guessed Channel Layout for Input Stream #1.0 : stereo
Input #1, alsa, from ‚hw:0,0‘:
Duration: N/A, start: 1528115857.694358, bitrate: 1536 kb/s
Stream #1:0: Audio: pcm_s16le, 48000 Hz, stereo, s16, 1536 kb/s
Any ideas?
Hi Rulet,
sounds to me that you did not set up an ALSA loopback device or that you are recording the wrong device. Have a look at the video I posted and check the output of “arecord -l” to find the ID of the loopback device.
Best regards,
h0nk3ym0nk3y