004-screencasts.html (4532B)
1 <p>On Monday 2020-03-16 the buildings of the danish public 2 sector were closed as an emergency response to COVID-19. This 3 includes Aarhus University where I teach two undergraduate courses. 4 The university asks lecturers to move their teaching to digital 5 platforms. As many times before, this requires creative thinking 6 for those of us who do not use Microsoft and Apple products.</p> 7 8 <p>I needed a way to record my pdf slideshows while talking over 9 the presentation. Ideally, I also wanted the ability to show the 10 video of my webcam as an overlay in an attempt to make the presentation 11 a bit more engaging when explaining complex parts.</p> 12 13 <p>Fortunately, <a href="https://ffmpeg.org">ffmpeg(1)</a> makes 14 it easy to record the screen and laptop audio. I want to keep the 15 fan noise low during recording by applying minimal compression and 16 encoding. The following shell script serves the purpose of starting 17 and stopping recording:</p> 18 19 <pre><code>#!/bin/sh 20 lockfile=/tmp/screenrecord.pid 21 22 startrecording() { 23 out="$HOME/screenrecord-$(date '+%Y-%m-%d_%H:%M:%S').mkv" 24 ffmpeg -y \ 25 -f x11grab \ 26 -framerate 60 \ 27 -s "$(xdpyinfo | grep dimensions | awk '{print $2}')" \ 28 -i $DISPLAY \ 29 -f sndio -i default \ 30 -r 30 \ 31 -c:v libx264rgb -crf 0 -preset ultrafast -c:a flac \ 32 "$out" >/dev/null 2>&1 & 33 printf '%s' "$!" > "$lockfile" 34 35 sleep 1 36 if [ ! -f "$out" ]; then 37 echo 'error: ffmpeg recording did not start' >&2 38 notify-send -u CRITICAL "${0##*/}" 'ffmpeg recording did not start' 39 rm -f "$lockfile" 40 exit 1 41 fi 42 } 43 44 stoprecording() { 45 kill "$(cat "$lockfile")" 46 rm -f "$lockfile" 47 notify-send "${0##*/}" 'recording ended' 48 } 49 50 if [ -f "$lockfile" ]; then 51 stoprecording 52 else 53 startrecording 54 fi 55 </code></pre> 56 57 <p>I have bound the above script to the key binding Alt+r which 58 makes it easy to start and stop recording in my X session.</p> 59 60 <p>On Linux systems, the sound driver <b>sndio</b> should be replaced 61 by <b>alsa</b> in the above ffmpeg(1) command. Audio recording is 62 disabled by default on OpenBSD, but can be permanently enabled with 63 the following commands:</p> 64 65 <pre><code># sysctl kern.audio.record=1 66 # echo kern.audio.record=1 >> /etc/sysctl.conf 67 </code></pre> 68 69 <p>On OpenBSD I can show the webcam video feed with the <a 70 href="https://man.openbsd.org/man1/video.1">video(1)</a> command. 71 The following script toggles the video feed:<p> 72 73 <pre><code>#!/bin/sh 74 # remember to `chown $USER /dev/video0` 75 if pgrep video >/dev/null 2>&1; then 76 pkill video 77 else 78 nohup video -s 320 >/dev/null 2>&1 & 79 fi 80 </code></pre> 81 82 <p>On Linux, the command <strong>mpv /dev/video0</strong> can take 83 place of the video(1) command above. I have the above script bound 84 to the keybinding Alt+v so I can quickly show and hide my face while 85 recording.</p> 86 87 <p>I set <a href="https://dwm.suckless.org">dwm(1)</a>, my window 88 manager, to open the video feed as a floating window on the bottom 89 right of the screen. The full dwm configuration can be found <a 90 href="https://src.adamsgaard.dk/dwm">here</a>.</p> 91 92 <p>When I am done recording a lecture, I encode and compress the 93 video file to save bandwidth during upload. The following script 94 encodes all input files and reduces file size to roughly 15% without 95 concievable loss in quality:</p> 96 97 <pre><code>#!/bin/sh 98 99 encode() { 100 ffmpeg -y -i "$1" \ 101 -c:v libx264 -threads 0 -preset faster -pix_fmt yuv420p \ 102 -c:a aac -crf 10 \ 103 "${1%.*}_out.mp4" 104 } 105 106 for f in "$@"; do 107 encode "$f" 108 done 109 </code></pre> 110 111 <p>If there is a delay between video and audio, this can also be 112 adjusted using ffmpeg(1). I correct for a 0.3 s delay that I 113 encounter when recording on my laptop:</p> 114 115 <pre><code>#!/bin/sh 116 117 synchronize() { 118 ffmpeg -y -i "$1" \ 119 -itsoffset 0.300 \ 120 -i "$1" \ 121 -map 0:v -map 1:a \ 122 -c copy \ 123 "${1%.*}_out.${1##*.}" 124 } 125 126 for f in "$@"; do 127 synchronize "$f" 128 done 129 </code></pre> 130 131 <figure class="pagefigure"> 132 <video poster="video/screencast.jpg" style="object-fit:fill;" 133 controls preload="none" class="mediaframe"> 134 <source src="video/screencast.webm" type="video/webm"> 135 <source src="video/screencast.ogv" type="video/ogg"> 136 <source src="video/screencast.mp4" type="video/mp4"> 137 <a href="video/screencast.mp4">Link</a> 138 </video> 139 <figcaption> 140 Example screen recording using ffmpeg(1) and video(1) 141 with the above scripts. 142 </figcaption> 143 </figure> 144