在「用 Bash 脚本写一个截屏工具」一文的后记里,我将截屏脚本略加改动,得到了一个可录制屏幕中指定窗口区域的脚本。翻手为云,覆手为雨,全拜 ffmpeg 所赐。

屏幕录制示例

我毫无新意地将这个录制屏幕的脚本取名为 recorder,内容为:

#!/bin/bash
NAME=$(date +"%Y-%m-%d %T" | sed -e "s/ /-/g; s/:/-/g")
RECORD=/tmp/${NAME}.mkv
OUTPUT=/tmp/output-${NAME}.mkv

# 获取屏幕分辨率
SCREEN=$(xrandr | grep -o "current [0-9]* x [0-9]*" | sed -e 's/current *//g')
SCREEN_W=$(echo $SCREEN | sed -e 's/ x [0-9]*//')
SCREEN_H=$(echo $SCREEN | sed -e 's/[0-9]* x //')

# 获取窗口几何参数
declare -a WIN_PARAMS
WIN_PARAMS=($(xwininfo | sed -n -e '/^[[:space:]]*Absolute ..*[XY]/p; 
                      /^[[:space:]]*Relative ..*[XY]/p; 
                      /^[[:space:]]*Width:/p; 
                      /^[[:space:]]*Height:/p' | awk 'BEGIN{FS=":"}{print $2}'))

# 构造理想中的截图区。
# 之所以如此,与 xwininfo 输出的窗口左上角相对坐标有关。
MARGIN=${WIN_PARAMS[2]}
WIN_X=$((${WIN_PARAMS[0]} - ${WIN_PARAMS[2]}))
WIN_Y=$((${WIN_PARAMS[1]} - ${WIN_PARAMS[3]}))
WIN_W=$((${WIN_PARAMS[4]} + ${WIN_PARAMS[2]} + $MARGIN))
WIN_H=$((${WIN_PARAMS[5]} + ${WIN_PARAMS[3]} + $MARGIN))

# 截图区越界处理
if (($WIN_X < 0)); then WIN_X=0; fi
if (($WIN_Y < 0)); then WIN_Y=0; fi
if (($WIN_W + $WIN_X > $SCREEN_W)); then WIN_W=$(($SCREEN_W - $WIN_X)); fi
if (($WIN_H + $WIN_Y > $SCREEN_H)); then WIN_H=$(($SCREEN_H - $WIN_Y)); fi

# 录制指定窗口区域
ffmpeg -video_size ${WIN_W}x${WIN_H} \
       -framerate 30 -f x11grab \
       -i :0.0+${WIN_X},${WIN_Y} \
       -c:v libx264rgb -crf 0 -preset ultrafast $RECORD

# 视频后处理
ffmpeg -i $RECORD -c:v libx264rgb -crf 0 -preset veryslow $OUTPUT

然后有些惋惜,觉得没法像截屏脚本那样,可以绑定到桌面环境的某个快捷键上。原因是,ffmpeg 在录制屏幕时,需要我在其运行的命令行窗口里摁一下 q 键方能结束屏幕录制。当时觉得,无解。截屏脚本在抓到屏幕画面后会自动退出,所以不存在这样的问题。

但是,刚才准备睡觉时,忽然觉得自己实在是迂腐得很。我可以将桌面环境的快捷键绑定到一个可以运行命令行窗口的脚本上,然后在这个脚本里将命令行窗口和 recorder 建立联系。

脑洞一旦打开,就去调研了一下我的桌面环境的命令行窗口程序 mate-terminal,发现它的确可以允许我以参数的形式传给它 recorder 脚本并由它负责运行:

$ mate-terminal -e recorder

事实上,在我的桌面环境里,没必要去写一个运行 mate-terminal 的脚本,只需要在桌面快捷键绑定设置里直接为带参数的 mate-terminal 绑定一个快捷键即可。

屏幕录制快捷键


garfileo
6k 声望1.9k 粉丝

这里可能不会再更新了。