t004-screencasts.html - adamsgaard.dk - my academic webpage
(HTM) git clone git://src.adamsgaard.dk/adamsgaard.dk
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
t004-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