GOPHERSPACE.DE - P H O X Y
gophering on adamsgaard.dk
# RECORDING SCREENCASTS AND LECTURES ON OPENBSD AND LINUX 

On Monday 2020-03-16 the buildings of the danish public sector were
closed as an emergency response to COVID-19. This includes Aarhus
University where I teach two undergraduate courses. The university
asks lecturers to move their teaching to digital platforms. As many
times before, this requires creative thinking for those of us who
do not use Microsoft and Apple products.

I needed a way to record my pdf slideshows while talking over the
presentation.  Ideally, I also wanted the ability to show the video
of my webcam as an overlay in an attempt to make the presentation
a bit more engaging when explaining complex parts.

Fortunately, [1]ffmpeg(1) makes it easy to record the screen and
laptop audio.  I want to keep the fan noise low during recording
by applying minimal compression and encoding. The following shell
script serves the purpose of starting and stopping recording:

    #!/bin/sh
    lockfile=/tmp/screenrecord.pid

    startrecording() {
        out="$HOME/screenrecord-$(date '+%Y-%m-%d_%H:%M:%S').mkv"
        ffmpeg -y \
            -f x11grab \
            -framerate 60 \
            -s "$(xdpyinfo | grep dimensions | awk '{print $2}')" \
            -i $DISPLAY \
            -f sndio -i default \
            -r 30 \
            -c:v libx264rgb -crf 0 -preset ultrafast -c:a flac \
            "$out" >/dev/null 2>&1 &
        printf '%s' "$!" > "$lockfile"

        sleep 1
        if [ ! -f "$out" ]; then
            echo 'error: ffmpeg recording did not start' >&2
            notify-send -u CRITICAL "${0##*/}" 'ffmpeg recording did not start'
            rm -f "$lockfile"
            exit 1
        fi
    }

    stoprecording() {
        kill "$(cat "$lockfile")"
        rm -f "$lockfile"
        notify-send "${0##*/}" 'recording ended'
    }

    if [ -f "$lockfile" ]; then
        stoprecording
    else
        startrecording
    fi

I have bound the above script to the key binding Alt+r which makes
it easy to start and stop recording in my X session.

On Linux systems, the sound driver sndio should be replaced by alsa
in the above ffmpeg(1) command.  Audio recording is disabled by
default on OpenBSD, but can be permanently enabled with the following
commands:

    # sysctl kern.audio.record=1
    # echo kern.audio.record=1 >> /etc/sysctl.conf

On OpenBSD I can show the webcam video feed with the [2]video(1)
command. The following script toggles the video feed:

    #!/bin/sh
    # remember to `chown $USER /dev/video0`
    if pgrep video >/dev/null 2>&1; then
        pkill video
    else
        nohup video -s 320 >/dev/null 2>&1 &
    fi

On Linux, the command mpv /dev/video0 can take place of the video(1)
command above. I have the above script bound to the keybinding Alt+v
so I can quickly show and hide my face while recording.

I set [3]dwm(1), my window manager, to open the video feed as a
floating window on the bottom right of the screen.  The full dwm
configuration can be found [4]here.

When I am done recording a lecture, I encode and compress the video
file to save bandwidth during upload. The following script encodes
all input files and reduces file size to roughly 15% without
concievable loss in quality:

    #!/bin/sh

    encode() {
        ffmpeg -y -i "$1" \
            -c:v libx264 -threads 0 -preset faster -pix_fmt yuv420p \
            -c:a aac -crf 10 \
            "${1%.*}_out.mp4"
    }

    for f in "$@"; do
        encode "$f"
    done

If there is a delay between video and audio, this can also be
adjusted using ffmpeg(1).  I correct for a 0.3 s delay that I
encounter when recording on my laptop:

    #!/bin/sh

    synchronize() {
        ffmpeg -y -i "$1" \
            -itsoffset 0.300 \
            -i "$1" \
            -map 0:v -map 1:a \
            -c copy \
            "${1%.*}_out.${1##*.}"
    }

    for f in "$@"; do
        synchronize "$f"
    done

[5]Example screen recording using ffmpeg(1) and video(1) with the
above scripts.

References:

[1] https://ffmpeg.org/
[2] https://man.openbsd.org/man1/video.1
[3] https://dwm.suckless.org/
[4] https://src.adamsgaard.dk/dwm/
[5] https://adamsgaard.dk/video/screencast.mp4