Skip to content

Instantly share code, notes, and snippets.

@slhck
Last active August 3, 2022 14:02
Show Gist options
  • Save slhck/2665965b76cc17ddce28cf23e78e2b58 to your computer and use it in GitHub Desktop.
Save slhck/2665965b76cc17ddce28cf23e78e2b58 to your computer and use it in GitHub Desktop.
capture_x11_ffmpeg.sh
#!/usr/bin/env bash
#
# Record the screen via x11grab and embed a timecode.
#
# Author: Werner Robitza
#
# License: MIT
#
# Version: 1.2.0
#
# History of changes:
#
# - 1.2.0: Add option for maximum time
# - 1.1.0: Set default output size to input size, and use 25 fps
# - 1.0.0: Initial release.
set -e
# ==============================================================================
# Checks
cd "$(dirname "$0")" || exit 1
for cmd in xrandr ffmpeg; do
if ! command -v "$cmd" >/dev/null 2>&1; then
echo "Error: '$cmd' is not installed."
exit 1
fi
done
# ==============================================================================
# fetch the display resolution of $DISPLAY with x11
DISPLAY="${DISPLAY:-:0}"
inputSize=$(xrandr --display "$DISPLAY" 2>/dev/null | tail -n 1 | awk '{print $1}')
if [ -z "$inputSize" ]; then
echo "Error: Unable to determine input size of display $DISPLAY."
echo "Make sure you've set the \$DISPLAY environment variable."
exit 1
fi
# ==============================================================================
# Set default variables
inputFps=25
# calculate aspect ratio by dividing the input size which is a string of the form "WxH" by the width
aspectRatio=$(echo "$inputSize" | awk -Fx '{print $1/$2}')
outHeight=${inputSize#*x}
outWidth=$(echo "$outHeight * $aspectRatio" | bc | awk '{printf "%d", $1}')
padding=10
quality=23
preset=faster
fontSize=$((outHeight/20))
# minimum font size is 24
if [ $fontSize -lt 24 ]; then
fontSize=24
fi
boxHeight=$((fontSize+padding))
boxWidth=$((fontSize*15))
if [ $boxWidth -gt $outWidth ]; then
boxWidth=$outWidth
fi
output="recording-$(date +%Y-%m-%d-%H-%M-%S).mkv"
outputTime=""
# ==============================================================================
# Option parsing
usage() {
echo "Usage: $0 [options]"
echo
echo "Record the display at \$DISPLAY and save to file."
echo
echo "Options:"
echo
echo " Input:"
echo " -s, --input-size <size> Input size (default: $inputSize)"
echo " -r, --input-fps <fps> Input fps (default: $inputFps)"
echo " --text-padding <padding> Padding (default: $padding)"
echo " --font-size <font size> Font size (default: $fontSize)"
echo
echo " Output:"
echo " -o, --output-file <output> Output file (default: $output)"
echo " -t, --output-time <outputTime> Output time (default: none)"
echo
echo " Encoding:"
echo " -q, --quality <quality> x264 CRF value (default: $quality)"
echo " -p, --preset <preset> x264 preset (default: $preset)"
echo " --output-height <height> Output height (default: $outHeight)"
echo
echo " General:"
echo " -h, --help Show this help and exit"
}
while [ $# -gt 0 ]; do
case "$1" in
-s|--input-size)
inputSize="$2"
shift 2
;;
-r|--input-fps)
inputFps="$2"
shift 2
;;
--text-padding)
padding="$2"
shift 2
;;
--font-size)
fontSize="$2"
shift 2
;;
-o|--output-file)
output="$2"
shift 2
;;
-t|--output-time)
outputTime="$2"
shift 2
;;
-q|--quality)
quality="$2"
shift 2
;;
-p|--preset)
preset="$2"
shift 2
;;
--output-height)
outHeight="$2"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo "Error: Unknown option '$1'."
usage
exit 1
;;
esac
done
echo "Settings: "
echo
echo " inputSize: $inputSize"
echo " inputFps: $inputFps"
echo " outHeight: $outHeight"
echo " padding: $padding"
echo " fontSize: $fontSize"
echo " boxHeight: $boxHeight"
echo " boxWidth: $boxWidth"
echo " output: $output"
echo " outputTime: $outputTime"
echo
# ==============================================================================
# Main code
if [ -n "$outputTime" ]; then
outputTime="-t $outputTime"
fi
set -x
ffmpeg \
-f x11grab -framerate "$inputFps" -video_size "$inputSize" -i "$DISPLAY" \
-filter:v "
settb=AVTB,
setpts='trunc(PTS/1K)*1K+st(1,trunc(RTCTIME/1K))-1K*trunc(ld(1)/1K)',
scale=-2:${outHeight},
drawbox=x=0:y=ih-h:color=black@0.4:width=${boxWidth}:height=${boxHeight}:t=fill,
drawtext=text='%{localtime}.%{eif\:1M*t-1K*trunc(t*1K)\:d}':fontcolor=white:fontsize=${fontSize}:x=${padding}:y=h-th-${padding},
format=yuv420p" \
-c:v libx264 \
-crf "$quality" \
-preset "$preset" \
$outputTime \
"$output"
set +x
echo "Done! Recording at: $output"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment