adamsgaard.dk

my academic webpage
git clone git://src.adamsgaard.dk/adamsgaard.dk # fast
git clone https://src.adamsgaard.dk/adamsgaard.dk.git # slow
Log | Files | Refs | README | LICENSE Back to index

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