Last active
October 15, 2022 20:10
-
-
Save funasoul/026fb941b46c5a22793d75073161294d to your computer and use it in GitHub Desktop.
ffmpeg だけでカメラONのスクリーンキャストを収録 for macOS, Linux and OpenBSD
This file contains hidden or 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
#!/usr/bin/env zsh | |
_has () { | |
return $( whence $1 &>/dev/null ) | |
} | |
getresolution () { | |
# returns current resolution | |
if [[ "$OSTYPE" == "darwin"* ]]; then | |
system_profiler SPDisplaysDataType | awk '/Resolution:/{print $2 "x" $4}' | |
elif _has xrandr; then | |
xrandr | awk '/\*/{print $1}' | |
elif _has xdpyinfo; then | |
xdpyinfo | awk '/dimensions/{print $2}' | |
fi | |
} | |
ffscast () { | |
# Requirement: | |
# - ffmpeg | |
# - getresolution() function | |
# - _has() function | |
# References: | |
# - https://gist.github.com/CAFxX/dafa30845b1b3872d29980b39cf15f58 | |
# - https://git.cbps.xyz/swindlesmccoop/not-just-dotfiles/src/branch/master/.local/bin/screencast | |
# - https://stackoverflow.com/a/47115192 | |
setopt LOCAL_OPTIONS NO_NOTIFY NO_MONITOR # be silent for background jobs | |
local TITLE | |
local CAMDEV | |
local SCRDEV | |
local SNDDEV | |
local fb # frame format | |
local cb # camera format | |
local sb # sound format | |
local probe_opt=() | |
local maxheight="1440" | |
local pix_opt=() | |
local capture_opt=() | |
local aenc_opt=() | |
local venc_opt=() | |
local screen_id="0" | |
local height | |
printf "Title: " | |
read TITLE | |
if [[ "$OSTYPE" == "darwin"* ]]; then | |
fb="avfoundation" | |
cb="avfoundation" | |
sb="avfoundation" | |
probe_opt=(-probesize 50M) | |
pix_opt=(-pix_fmt uyvy422) | |
capture_opt=(-capture_cursor 1 -capture_mouse_clicks 1) | |
aenc_opt=(-c:a libopus) | |
venc_opt=(-c:v hevc_videotoolbox -b:v 5000k) | |
local devs=$(ffmpeg -f $fb -list_devices true -i "" |& grep -i $fb | grep -v -e "mmhmm" -e "Reincubate" -e "Zoom" -e "Microsoft" -e "Virtual Desktop" -e "BlackHole") | |
local v=$(echo $devs | awk '/video device/,/audio device/' | cut -d']' -f 2-9 | grep -vi $fb) | |
local a=$(echo $devs | awk '/audio device/,/hoge/' | cut -d']' -f 2-9 | grep -vi $fb) | |
CAMDEV="$(echo $v | grep -i facetime | cut -d "[" -f2 | cut -d "]" -f1)" | |
echo $v | |
printf "Screen device (ex: 0, 1, 2): " | |
read SCRDEV | |
screen_id=$(echo $v | awk -v var="$SCRDEV" '$0 ~ var {print $4}') | |
echo $a | |
printf "Sound device (ex: 0, 1, 2): " | |
read SNDDEV | |
SNDDEV=":${SNDDEV}" | |
elif [[ "$OSTYPE" == "openbsd"* ]]; then | |
CAMDEV="/dev/video0" | |
SCRDEV=":0.0" | |
SNDDEV="snd/0" | |
fb="x11grab" | |
cb="v4l2" | |
sb="sndio" | |
venc_opt=(-c:v libx264) | |
if [ $(sysctl -n kern.audio.record) = 0 ]; then [ ~ ] | |
echo "Please exec 'doas sysctl kern.audio.record=1' for audio recording" | |
return | |
fi | |
if [ $(sysctl -n kern.video.record) = 0 ]; then [ ~ ] | |
echo "Please exec 'doas sysctl kern.video.record=1' for video recording" | |
return | |
fi | |
if [ ! -w /dev/video0 ]; then | |
echo "Please exec 'doas chown $USER /dev/video0' for video recording" | |
return | |
fi | |
else # Ubuntu | |
CAMDEV="/dev/video0" | |
SCRDEV=":0.0" | |
SNDDEV="default" # pacmd list-sources will list all devices | |
fb="x11grab" | |
cb="v4l2" | |
sb="pulse" | |
venc_opt=(-c:v libx264) | |
fi | |
# get minimal height from current resolution. requires getresolution() function. | |
local heights=( $(getresolution | awk '{n=split($0, ary, "x"); print(ary[2])}' ) ) | |
height=$heights[(( $screen_id + 1 ))] # zsh's array is one origin! | |
local minheight=$([ $height -le $maxheight ] && echo "$height" || echo "$maxheight") | |
TITLE="$(echo $TITLE | sed 's/ /_/g')" | |
local DIRNAME="$TITLE-$(date '+%s')" | |
local DIRPATH="$HOME/Downloads/screencasts/$DIRNAME" | |
mkdir -p $DIRPATH | |
ffmpeg -nostdin \ | |
-thread_queue_size 150 -f $fb ${probe_opt[@]} -framerate 30 ${pix_opt[@]} ${capture_opt[@]} -i "$SCRDEV" \ | |
-thread_queue_size 150 -f $cb -video_size vga -framerate 30 ${pix_opt[@]} -i "$CAMDEV" \ | |
-thread_queue_size 150 -f $sb -i "$SNDDEV" -filter_complex ' | |
[0]fps=fps=30[scr], | |
[scr]scale=-1:'$minheight'[scr], | |
[1]fps=fps=30[cam], | |
[cam]scale=320:-1,pad=320:'$minheight'[cam], | |
[scr][cam]hstack[vout], | |
[2]afftdn[aout] | |
'\ | |
-map '[vout]' ${venc_opt[@]} \ | |
-map '[aout]' ${aenc_opt[@]} -b:a 256k \ | |
-preset ultrafast $DIRPATH/final.mkv >/dev/null 2>&1 & | |
printf "Video and Audio recording started.\n\n" | |
printf "Press enter to stop recording" | |
read local lol | |
cd "$DIRPATH" | |
kill $(pgrep ffmpeg) | |
echo "Converting final.mkv to final.mp4 ..." | |
ffmpeg -v 0 -i final.mkv -q:a 0 -q:v 0 -strict -2 final.mp4 | |
echo "Done." | |
} | |
ffscast |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment