编写 bash 脚本, 实现一行命令得到 Android 手机录制屏幕 gif 动图文件.
博主使用 ubuntu 系统, shell 为 bash. 这个脚本也可以用在 mac 系统上.
听说 windows 系统出了 ubuntu on windows, 不知道能不能使用这个脚本.
Android 4.4 版本后系统内预置了一个 screenrecord 命令, 可以用来将屏幕录制为 MP4 格式. 具体命令格式可以通过 –help 参数查看:
$ adb shell screenrecord --help
Usage: screenrecord [options]
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 -i video.mp4 -r 5 'frames/frame-%03d.jpg'
其中: -r 5
代表抽取的帧率, 即每秒视频抽取 5 帧出来.
使用 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 -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 : [email protected]
#========================================================
# 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 file: $TMP_DIR/$OUTPUT_VIDEO_NAME"
MP4ToGIF $TMP_DIR/$OUTPUT_VIDEO_NAME
else
echo "* create screen record mp4 fail"
exit 2
fi
}
trap CTRL_C SIGINT
# catch script exit event
CLEAR_WORK() {
if [ -e $TMP_DIR ]; then
# since the tmp files have been put into /tmp/ dir, they will get
# removed on system reboot. thus we are in no hurry to remove them now.
# un-commit this line if you want to remove tmp files immediately after script run
#rm $TMP_DIR
echo
fi
}
trap "CLEAR_WORK" EXIT
#========================================================
function MP4ToGIF() {
echo "*** extract frames ***"
mkdir $TMP_DIR/frames
ffmpeg -i $1 -r $GIF_FPS "$TMP_DIR/frames/frame-%03d.jpg"
echo "*** convert frames to gif ***"
convert -delay $GIF_DELAY -loop 0 "$TMP_DIR/frames/*.jpg" $OUTPUT_FILE_DIR/$OUTPUT_FILE_NAME
}
#========================================================
if [ ! -d "$OUTPUT_FILE_DIR" ]; then
echo "* output dir not exists: $OUTPUT_FILE_DIR"
exit 1
fi
if [ ! -e $TMP_DIR ]; then
mkdir $TMP_DIR
fi
if [ ! -e $TMP_DIR ]; then
echo "* tmp dir not exists: $TMP_DIR"
exit 1
fi
echo "params: $RESOLUTION, $BIT_RATE, $GIF_FPS, $GIF_DELAY"
adb shell screenrecord --verbose --size $RESOLUTION --bit-rate $BIT_RATE $OUTPUT_VIDEO_DEVICE_DIR/$OUTPUT_VIDEO_NAME
开头定义的那几个数组, 是为了便于测试. 最终生成的 gif 文件也直接保存在了当前目录下.
主要是因为加上参数化, 代码会多很多, 就不容易找到主要功能了.
带参数化, 带简易帮助文档的完整脚本, 可以在下面链接中找到:
android_screen2gif.sh
使用前提:
脚本本身就是为了使用简单写的. 只需在命令行直接执行脚本, 即可开始手机屏幕录制. 因为是测试, 选在 /tmp 目录操作.
$ cd /tmp/
$ android_screen2gif.sh
params: 360x640, 1000000, 5, 20
Main display is 720x1280 @60.00fps (orientation=0)
Configuring recorder for 360x640 video/avc at 1.00Mbps
Content area is 360x640 at offset x=0 y=0
这时录制正在进行, 命令行挂起. 等你认为录制可以结束了, 按下 ctrl-c, 录制结束, 开始转换 gif 的步骤. 一般需要3到4秒, 录屏的 gif 就在当前目录生成了.
^Cstop recording. start convert...
[100%] /sdcard/screenrecord_0407090859.mp4
converting file: /tmp/android_screen_to_gif_0407090859/screenrecord_0407090859.mp4
*** extract frames ***
ffmpeg version 3.0.7-0ubuntu0.16.10.1 Copyright (c) 2000-2017 the FFmpeg developers
......
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/tmp/android_screen_to_gif_0407090859/screenrecord_0407090859.mp4':
......
Output #0, image2, to '/tmp/android_screen_to_gif_0407090859/frames/frame-%03d.jpg':
......
*** convert frames to gif ***
result gif file:
/tmp/android_screen_record.0407090859.gif
这一步输出较多, 用 ......
代替了部分输出. 最后那行就是最终生成的 gif 录屏文件了.
根据自测 及 最终 gif 生成的过程, 可以得到如下结论:
视频解析度参数:
宽高越大越清晰, 最终生成的 gif 文件越大. 这个是很明显的.
最好按手机竖屏显示的方式, 将解析度设置为 9:16 的比例. 如果设置为其他比例, 比如 480:480, 则录制出的视频会有很宽的黑边.
视频比特率参数:
先说结论: 比特率设置基本不会影响最终生成的 gif 文件质量.
因为最终 gif 文件来自视频抽帧, 视频比特率的大小对于比如每秒抽取10帧这样的需求, 对抽取出的图片清晰度影响不大. 因此为了中间文件更小, 建议把这个参数设低即可.
抽帧帧率 及 每帧间隔:
这两个参数对最终 gif 质量影响很大. 其中:
抽帧帧率越大, 最终 gif 质量越高;
每帧间隔越小, 最终 gif 质量越高.
如前述, 这两个参数必须成对设置. 如果这两个参数都取整数的话, 基本上可以设置的就下面这几对:
2, 50
4, 25
5, 20
10, 10
其中: 10, 10
这组, 设置每秒10帧, gif 每帧间隔 0.1 秒, 这样5秒的gif文件就要大概 10M 大小了. 2, 50
这组, 设置每秒2帧, gif 每帧间隔 0.5 秒, 最终gif文件卡顿就很严重了.
因此建议选取 5, 20
这组参数. 如果对gif质量要求很高, 可以试试 10, 10
这组参数.
综上, 小伙伴们可以自己尝试下设置不同的参数组合, 试几次就能体会该怎么设置了.
create gif from mp4 via command line
command convert doc
再次无耻的安利安利自己的脚本项目:
android_screen2gif.sh
原创文章, 转载请注明出处: http://blog.csdn.net/liuxu0703/article/details/69397154