Skip to content

Instantly share code, notes, and snippets.

@morgant
Forked from ekollof/screen-record.ksh
Created March 22, 2025 20:11
Show Gist options
  • Save morgant/c79c97f787600344825541d41729e5a2 to your computer and use it in GitHub Desktop.
Save morgant/c79c97f787600344825541d41729e5a2 to your computer and use it in GitHub Desktop.
Record your multihead OpenBSD desktop (probably some assembly required)
#!/bin/ksh
# Help message
usage() {
echo "Usage: $0 [-s screen] [-l] [-h]"
echo " -s screen Select screen number (0, 1, 2, etc.)"
echo " -l List available screens"
echo " -h Show this help message"
exit 1
}
# Function to list screens with xrandr
list_screens() {
echo "Available screens:"
xrandr --listactivemonitors | tail -n +2 | nl -v 0
}
# Function to get screen geometry for a given screen number
get_screen_geometry() {
screen_num=$1
echo "Debug: Looking for screen $screen_num"
# Get the selected monitor line
monitor_info=$(xrandr --listactivemonitors | tail -n +2 | sed -n "$((screen_num + 1))p")
echo "Debug: Monitor info: $monitor_info"
if [ -z "$monitor_info" ]; then
echo "Error: Screen $screen_num not found" >&2
exit 1
fi
# Get raw dimensions from xrandr --listmonitors (which shows actual pixels)
raw_info=$(xrandr | grep -A1 "^Screen" | tail -n1)
echo "Debug: Raw screen info: $raw_info"
# First try to get current resolution from xrandr output
current_mode=$(xrandr | grep -A1 "^$(echo "$monitor_info" | awk '{print $3}')" | grep -v "^--" | grep "*" | awk '{print $1}')
echo "Debug: Current mode: $current_mode"
if [ -n "$current_mode" ]; then
SCREEN_WIDTH=$(echo "$current_mode" | cut -d'x' -f1)
SCREEN_HEIGHT=$(echo "$current_mode" | cut -d'x' -f2)
else
# Fallback to parsing from monitor_info
SCREEN_WIDTH=$(echo "$monitor_info" | awk '{print $3}' | cut -d'/' -f1)
SCREEN_HEIGHT=$(echo "$monitor_info" | awk '{print $3}' | cut -d'x' -f2 | cut -d'/' -f1)
fi
# Extract offsets
SCREEN_OFFSET_X=$(echo "$monitor_info" | awk '{print $3}' | sed 's/.*+\([0-9]*\)+.*/\1/')
SCREEN_OFFSET_Y=$(echo "$monitor_info" | awk '{print $3}' | sed 's/.*+[0-9]*+\([0-9]*\)/\1/')
echo "Debug: Parsed values:"
echo "Width: $SCREEN_WIDTH"
echo "Height: $SCREEN_HEIGHT"
echo "Offset X: $SCREEN_OFFSET_X"
echo "Offset Y: $SCREEN_OFFSET_Y"
# Verify we got valid numbers
if [ -z "$SCREEN_WIDTH" ] || [ -z "$SCREEN_HEIGHT" ] || \
[ -z "$SCREEN_OFFSET_X" ] || [ -z "$SCREEN_OFFSET_Y" ]; then
echo "Error: Failed to parse screen dimensions" >&2
exit 1
fi
}
# Initialize variables
SCREEN=""
SCREEN_WIDTH=""
SCREEN_HEIGHT=""
SCREEN_OFFSET_X=""
SCREEN_OFFSET_Y=""
# Parse command line options
while getopts "s:lh" opt; do
case $opt in
s)
SCREEN=${OPTARG}
get_screen_geometry "$SCREEN"
;;
l)
list_screens
exit 0
;;
h)
usage
;;
*)
echo "Invalid option: -$OPTARG" >&2
usage
;;
esac
done
# If no screen specified or geometry not set, show usage
if [ -z "$SCREEN" ] || [ -z "$SCREEN_WIDTH" ]; then
echo "Error: No screen selected or screen geometry not found" >&2
usage
fi
# Get current timestamp
NAME=$(date '+%Y-%m-%d_%H%M%S')
echo "Recording screen $SCREEN (${SCREEN_WIDTH}x${SCREEN_HEIGHT} at offset ${SCREEN_OFFSET_X},${SCREEN_OFFSET_Y})"
ffmpeg -hwaccel vaapi -vaapi_device /dev/dri/renderD128 \
-f sndio -thread_queue_size 1024 -i snd/0.mon \
-f sndio -thread_queue_size 1024 -i snd/1 \
-f x11grab -thread_queue_size 1024 -probesize 32 -draw_mouse 1 \
-video_size ${SCREEN_WIDTH}x${SCREEN_HEIGHT} -r 30 \
-i :0.0+${SCREEN_OFFSET_X},${SCREEN_OFFSET_Y} \
-filter_complex "\
[0:a]volume=4.0,pan=stereo|c0=c0|c1=c1[desktop];\
[1:a]volume=3.0,acompressor=threshold=0.125:ratio=4:attack=200:release=1000,dynaudnorm=f=10:g=3:p=0.9,pan=stereo|c0=c0|c1=c1[mic];\
[desktop][mic]amix=inputs=2:duration=first[aout]" \
-map 2:v \
-map '[aout]' \
-c:v h264_vaapi \
-vf 'format=nv12|vaapi,hwupload' \
-qp 0 \
-c:a flac \
-b:a 160k \
-ar 48000 \
-ac 2 \
-fps_mode cfr \
-async 1 \
-flags +low_delay \
-fflags +nobuffer \
-y \
"$HOME/Videos/$NAME.mkv"
echo "Recording started in $HOME/Videos/$NAME.mkv"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment