2014年1月4日星期六

Linux下流畅地录屏

用过很多Linux下的录屏工具,基本分成三类,FFmpeg 后端、GStreamer 后端、自己实现后端。有很多录屏软件让我不满意。有的在高分辨率下有很严重的跳帧问题,最终导致音画不同步。有的不支持录制系统的声音。还有的没有精细的配置功能。而且,我希望能够输出无损压缩的媒体格式,便于后期处理。
分享我的屏幕录制命令如下:
sleep 5; ffmpeg -y -f x11grab -s 1920x1080 -framerate 30 -i :0 -vf 'setpts=(RTCTIME-RTCSTART)/(TB*1000000)' -c:v libx264 -profile:v high444 -preset:v veryfast -qp:v 0 -pix_fmt yuv444p screencast.mkv
要注意以下几点:
-s 1920x1080 换成自己的屏幕分辨率,
-framerate 30 换成录屏的帧率,
-i :0 换成当前的 $DISPLAY 环境变量值,
-i alsa_output.xxxxxxxxxxxxx.0.analog-stereo.monitor 的参数,请看下面。
这样录制下来的视频文件是 H.264 YUV444P 无损的,便于后期剪辑。如果要分享到互联网,请在二次压制的时候加上 -pix_fmt 420p,因为很多网络媒体播放器不支持 YUV444P。sleep 5 是给自己准备最小化终端窗口的时间。

录制系统声音

再加一个 PulseAudio 的输入:
sleep 5; ffmpeg -y -f x11grab -s 1920x1080 -framerate 30 -i :0 -f pulse -i alsa_output.xxxxxxxxxxxxx.0.analog-stereo.monitor -vf 'setpts=(RTCTIME-RTCSTART)/(TB*1000000)' -af asetpts=N/SR/TB,apad -shortest -c:v libx264 -profile:v high444 -preset:v veryfast -qp:v 0 -pix_fmt yuv444p -c:a flac screencast.mkv
-i alsa_output.xxxxxxxxxxxxx.0.analog-stereo.monitor 的获取方法如下:
执行 pactl list | grep -A2 'Source #',会看到如下两行(如果你只有一块声卡的话):
Source #0
        State: IDLE
        Name: alsa_output.xxxxxxxxxxxxx.0.analog-stereo.monitor
--
Source #1
        State: SUSPENDED
        Name: alsa_output.xxxxxxxxxxxxx.0.analog-stereo
Name 后面有 .monitor 的表示系统声音,另一个表示麦克风。

音画同步问题

如果出现音画不同步,请尝试 -af 指定以下几种参数的组合:
-af aresample=async=1
-af asetpts=N/SR/TB,apad -shortest
-af 'asetpts=(RTCTIME-RTCSTART)/(TB*1000000)'

跳帧问题

如果遇到跳帧,可以适当降低帧率,设置 -threads auto;或者将 -preset:v veryfast 换成 -preset:v ultrafast;或者试试看 FFv1、FFvHuff、HuffYUV 等无损编码器和 MPEG1Video、MPEG2Video、MJPEG 等复杂度低的编码器,或者把音频编码器换成 pcm_s16le;或者换用 MPEG-TS、FLV 等容器格式。
还可以试试看 Apple ProRes 编码器。它有着很快的速度和接近无损的效果。FFmpeg 自带三个 ProRes 编码器(proresprores_awprores_ks)和两个解码器(proresprores_lgpl)。这些编解码器性能不同,功能各异,请自己尝试参数配置。
如果录屏让你的 SCSI 硬盘不堪重负,请检查 SCSI 控制器是否在 AHCI 模式而不是 IDE 模式。(如果你已经安装了 Linux 或 *BSD 以外的系统,请不要修改 SCSI 模式;我的 7200rpm 笔记本电脑硬盘在 IDE 模式下只有 25MiB/s 的写入速度,而切换到 AHCI 模式下有 90MiB/s 写入速度。)
如果有以上方法都不能解决的音画同步问题,建议使用两个独立的 FFmpeg 进程来分别录制图像和声音。但是会带来后期处理的麻烦。

后期压制

将输出的 screencast.mkv 压制成 MP4 输出并分享到网络,可以用类似这样的命令:
ffmpeg -i screencast.mkv -movflags +faststart -c:v libx264 -profile:v high -level:v 4.1 -preset:v veryslow -b:v 4096k -pix_fmt yuv420p -c:a libfdk_aac -profile:a aac_he -b:a 256k my_screencast.mp4
其中 -c:a libfdk_aac 根据自己的 AAC 编码器来修改(但是只有 libfdk_aac 支持 -profile:a aac_he,而且质量最好),如果不知道自己装了哪些编码器,就依次尝试:
-c:a libfdk_aac
-c:a libfaac
-c:a aac -strict -2
如果 QuickTime/MP4 文件要通过网络分享,建议使用 -movflags +faststart 参数。它把关键数据移动到文件开头,有利于缓冲。