目的
编写 bash 脚本, 实现一行命令得到 Android 手机录制屏幕 gif 动图文件.
博主使用 ubuntu 系统, shell 为 bash. 这个脚本也可以用在 mac 系统上.
听说 windows 系统出了 ubuntu on windows, 不知道能不能使用这个脚本.
原理
adb shell screenrecord
Android 4.4 版本后系统内预置了一个 screenrecord 命令, 可以用来将屏幕录制为 MP4 格式. 具体命令格式可以通过 –help 参数查看:
$ adb shell screenrecord --help
Usage: screenrecord [options] <filename>
Android screenrecord v1.2. Records the device's display to a .mp4 file.
Options:
--size WIDTHxHEIGHT
Set the video size, e.g. "1280x720". Default is the device's main
display resolution (if supported), 1280x720 if not. For best results,
use a size supported by the AVC encoder.
--bit-rate RATE
Set the video bit rate, in bits per second. Value may be specified as
bits or megabits, e.g. '4000000' is equivalent to '4M'. Default 4Mbps.
--bugreport
Add additional information, such as a timestamp overlay, that is helpful
in videos captured to illustrate bugs.
--time-limit TIME
Set the maximum recording time, in seconds. Default / maximum is 180.
--verbose
Display interesting information on stdout.
--help
Show this message.
Recording continues until Ctrl-C is hit or the time limit is reached.
举例:
adb shell screenrecord --size "360x640" --bit-rate 2000000 /sdcard/android_screenrecord_test.mp4
上面的命令将把所连接的手机屏幕录制为 宽高 360x640, 比特率 2M 的视频, 保存为手机 sd 卡根目录下的 android_screenrecord_test.mp4 文件.
该命令会持续录制, 直到用 ctrl-c 终止命令, 那么录制也就结束了.
也可以用 –time-limit TIME 参数来预先指定录制时长, 到时间会自动结束. 默认的最大时长为 3 分钟.
ffmpeg
使用 ffmpeg 抽帧的命令将视频提取为一系列图片:
ffmpeg -i video.mp4 -r 5 'frames/frame-%03d.jpg'
其中: -r 5
代表抽取的帧率, 即每秒视频抽取 5 帧出来.
convert
使用 imagemagick 包中的 convert 命令将一系列图片组合为 gif 动图格式:
convert -delay 20 -loop 0 *.jpg myimage.gif
其中: -delay 20
代表所生成的 gif 动图每帧之间的时间间隔, 即每 0.2 秒显示下一帧.
如果系统内还没有 convert 命令, 可以用如下命令安装:
sudo apt-get install imagemagick
博主使用 ubuntu 16.10, 这个命令是预置在系统里的, 不需要安装.
ffmpeg 及 convert 参数设置
上面两个命令中, ffmpeg -r 5
和 convert -delay 20
这两个参数值, 分别是 视频抽帧间隔 和 gif每帧间隔, 假设其分别为 video_fps 和 gif_delay, 那么这两个参数在设置时必须满足如下条件:
video_fps * gif_delay = 100
如果乘积小于 100, 则生成的 gif 会比原本的播放速度快;
如果乘积大于 100, 则生成的 gif 会比原本的播放速度慢.
至于原因, 结合上面对这两个参数的介绍, 思考一下就明白了.
捕获录制结束事件
上面三个命令分开调用, 实现录屏为 gif 已经相当简单了.
如果要将三条命令写在一个脚本里, 在一个过程中完成功能, 第一个要解决的是如何捕获录制结束事件, 即 ctrl-c 命令.
在 bash 中可以通过下面脚本实现:
# catch ctrl-c signal
CTRL_C() {
# ctrl-c hit, do something
}
trap CTRL_C SIGINT
有了这个方法获取录制结束事件, 再往下就简单了.
这里遇到一个坑, 就是如果捕获 ctrl-c 后直接开始转换 gif 的操作, 会失败. 试过几次后, 发现是 ctrl-c 后其实 Android 的 screenrecord 命令并没有处理完, 这时候的视频还不可用. 解决的办法简单粗暴, 让脚本原地 sleep 2秒, 再去操作所生成的 MP4 文件就可用了.
最终脚本
也不知道该写些啥了, 直接贴出完整脚本吧:
#!/bin/bash
# author : liuxu-0703@163.com
#========================================================
# define param group here
QUALITY_1=("360x640" 1000000 4 25)
QUALITY_2=("360x640" 1000000 5 20)
QUALITY_3=("360x640" 1000000 10 10)
QUALITY_4=("720x1280" 1000000 4 25)
QUALITY_5=("720x1280" 1000000 5 20)
#========================================================
QUALITY=(${QUALITY_2[@]})
RESOLUTION=${QUALITY[0]}
BIT_RATE=${QUALITY[1]}
GIF_FPS=${QUALITY[2]}
GIF_DELAY=${QUALITY[3]}
# GIF_FPS and GIF_DELAY must meet the following condition:
# GIF_FPS * GIF_DELAY = 100
OUTPUT_FILE_NAME=android_screen_record.$(date +%m%d%H%M%S).gif
OUTPUT_FILE_DIR=$(pwd)
OUTPUT_VIDEO_NAME=screenrecord_$(date +%m%d%H%M%S).mp4
OUTPUT_VIDEO_DEVICE_DIR=/sdcard
TMP_DIR=/tmp/android_screen_to_gif_$(date +%m%d%H%M%S)
RECORDING=true
# you may use adb by absolute file path. if so, specify it here
ADB="adb"
#========================================================
# catch ctrl-c signal
CTRL_C() {
if $RECORDING; then
echo "stop recording. start convert..."
RECORDING=false
else
# ctrl-c hit but not for stop recording, just exit.
exit $?
fi
# adb screenrecord may still deal with mp4 file creating,
# just wait for it a little while.
sleep 2s
adb pull $OUTPUT_VIDEO_DEVICE_DIR/$OUTPUT_VIDEO_NAME $TMP_DIR
if [ -f $TMP_DIR/$OUTPUT_VIDEO_NAME ]; then
# remove video on phone
adb shell rm $OUTPUT_VIDEO_DEVICE_DIR/$OUTPUT_VIDEO_NAME
echo "converting fil