Last active
October 16, 2022 19:49
-
-
Save 0E9B061F/54fb06977c07a8a84c29a397424b9abe to your computer and use it in GitHub Desktop.
A simple screen recorder using ffmpeg, designed to be used headlessly, e.g., from a keyboard shortcut
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# ~/bin/recorder | |
# | |
# A simple screen recorder using ffmpeg, designed to be used headlessly, e.g., | |
# from a keyboard shortcut. Calling the script again while another instance is | |
# running will kill the running instance, allowing you to toggle recording. | |
# | |
# REQUIRES: VAAPI, ffmpeg, notify-send, yad, beep | |
# | |
# * Recordings are placed in ~/recordings, which will be created if it does not | |
# exist. | |
# * A symlink to the latest recording is created at ~/recordings/latest.mp4 | |
# * A PID file is created at ~/.recorder.pid | |
# * A PNG image is expected at ~/.recording.png, which will be used as a system | |
# tray icon. Example: https://0e9b061f.github.io/files/recording.png | |
# | |
# A system tray icon is created during recording to alert the user when running | |
# headlessly. There will be no indication that recording is occuring if you | |
# don't have a system tray. | |
# | |
# A script like `vlc ~/recordings/latest.mp4` may be useful to view recordings | |
# immediately. | |
read -r -d '' USAGE <<'EOF' | |
A simple screen recorder designed for headless use | |
recorder [-f FPS] [-q CQP] [-t TIME] | |
-f FPS | |
Frames per second to record | |
Default: 15 | |
-q CQP | |
A number between 0-51. Controls recording quality. Higher numbers mean | |
lower quality, and smaller files. Zero is lossless. | |
Default: 26 | |
-t TIME | |
End recording after TIME seconds | |
EOF | |
LIMIT= | |
FR="15" | |
CQP="26" | |
while getopts 'ht:f:q:' arg; do | |
case "${arg}" in | |
h) echo "${USAGE}"; exit 0 ;; | |
t) LIMIT="${OPTARG}" ;; | |
f) FR="${OPTARG}" ;; | |
q) CQP="${OPTARG}" ;; | |
*) exit 1 ;; | |
esac | |
done | |
shift $((OPTIND - 1)) | |
OUT="$(date +%s)" | |
PIDF="${HOME}/.recorder.pid" | |
ICON="${HOME}/.recording.png" | |
OUTD="${HOME}/recordings" | |
OUTF="${OUTD}/${OUT}.mp4" | |
LINK="${OUTD}/latest.mp4" | |
TIMER= | |
YAD= | |
function msg() { | |
local msg | |
msg="${1}" | |
echo "${msg}" | |
notify-send -t 4000 "RECORDER" "${msg}" | |
} | |
function err() { | |
local msg | |
msg="${1}" | |
echo "ERROR: ${msg}" | |
notify-send -u critical -t 8000 "RECORDER ERROR" "${msg}" | |
} | |
function smite() { | |
kill "${1}" >& /dev/null | |
} | |
function on_exit() { | |
[[ -n "${TIMER}" ]] && smite "${TIMER}" | |
[[ -n "${YAD}" ]] && smite "${YAD}" | |
rm -f "${PIDF}" | |
ln -sf "${OUTF}" "${LINK}" | |
beep -f 1000 -l 8 -D 0 | |
} | |
mkdir -p "${OUTD}" | |
if [[ -f "${PIDF}" ]]; then | |
PID="$(cat "${PIDF}")" | |
if ps -p "${PID}" >& /dev/null; then | |
if smite "${PID}"; then msg "Ended recording." | |
else | |
err "Unable to kill recorder" | |
exit 1 | |
fi | |
else | |
if rm "${PIDF}"; then "${BASH_SOURCE[0]}" ${@} | |
else | |
err "Unable to remove stale PID file (${PIDF})" | |
exit 1 | |
fi | |
fi | |
else | |
trap on_exit EXIT | |
echo "Begin recording:" | |
if [[ -f "${ICON}" ]]; then | |
yad --notification --command='' --image="${ICON}" & | |
YAD="${!}" | |
fi | |
beep -f 2000 -l 6 -D 0 | |
ffmpeg \ | |
-hwaccel vaapi \ | |
-hwaccel_output_format vaapi \ | |
-f x11grab \ | |
-framerate "${FR}" \ | |
-i "${DISPLAY}" \ | |
-c:v h264_vaapi \ | |
-compression_level 1 \ | |
-vaapi_device /dev/dri/renderD128 \ | |
-vf 'format=nv12,hwupload' \ | |
-f mp4 \ | |
-threads 12 \ | |
-rc_mode 1 \ | |
-qp ${CQP} \ | |
"${OUTF}" & | |
FFPID="${!}" | |
echo "${FFPID}" > "${PIDF}" | |
if [[ -n "${LIMIT}" ]]; then | |
( | |
sleep "${LIMIT}" | |
smite "${FFPID}" && msg "Ended recording." | |
) & | |
TIMER="${!}" | |
fi | |
wait "${FFPID}" | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment