一键生成 Android 录屏 gif 的脚本

目的

编写 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 5convert -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

时间: 2024-10-20 09:12:37

一键生成 Android 录屏 gif 的脚本的相关文章

Android录屏命令、Android录Gif、Android录视频

NoHttp开源地址:https://github.com/yanzhenjie/NoHttp NoHttp具体使用文档已公布,你想知道的全都有,请点我移步! 版权声明:转载请注明本文转自严振杰的博客: http://blog.yanzhenjie.com 演示 大家看博客时常常看到以下这样的图片,都非常想知道怎么做的吧,好在自己写博客时也把操作录下来: 这个图是我还有一个博客的图讲Android三级联动和ListView单选多选的,博客和源代码传送门,如今呢就一步步教大家怎么来做这个图. 上方

Android录屏应用开发研究

1截屏接口 在Android5.0之前如果希望截图屏幕,是需要获取系统root权限的.但在Android5.0之后Android开放了新的接口android.media.projection,开发者使用该接口,第三方应用程序无需再获取系统root权限也可以直接进行屏幕截图操作了.查询其官方api可知,该接口主要用来"屏幕截图"操作和"音频录制"操作,这里只讨论用于屏幕截图的功能.由于使用了媒体的映射技术手段,故截取的屏幕并不是真正的设备屏幕,而是截取的通过映射出来的

Android tips(九)--&gt;Android录屏与转化gif图

转载请标明出处:一片枫叶的专栏 最近有同学问我android手机的录屏以及转化成gif图是如何实现的?今天正好就讲讲android的录屏与转化gif操作.整个Android系统的录制与转化GIF图是分为两个部分,录制过程与转化过程,下面就详细的介绍一下这两个部分的具体过程. android手机的录屏操作 android手机也有一些录制屏幕的软件,但是作为程序员还是推荐使用adb 命令实现对屏幕操作的录制操作的,而下面我们就介绍一下实现屏幕录制功能的adb命令:screenrecord. 关于sc

Android录屏流程

1.权限申明 <uses-permission android:name="android.permission.RECORD_AUDIO" /> 2.请求录屏 private MediaProjectionManager mMediaProjectionManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mBi

Android5.0免Root截屏,录屏

http://blog.csdn.net/wds1181977/article/details/52174840 MediaProjection介绍 MediaProjection可以用来捕捉屏幕,具体来说可以截取当前屏幕和录制屏幕视频.MediaProjection由MediaProjectionManager来管理和获取. 使用步骤 首先获取MediaProjectionManager,和其他的Manager一样通过 Context.getSystemService() 传入参数MEDIA_

[开源] android apk 一键生成混淆文件 脚本分享 (python)

今天做的项目有个需求.要把我们的apk 混淆一下. 于是花了一下午的时间研究了一下,用python 写了个一键生成的脚本. 原理: 我的开发环境是  adt bundle 是android sdk 的集成开发环境,自带了ProGuard. 只需要导出的时候,在project.properties 打开注释的代码. 然后选择 export 导出apk 就自动混淆了,ProGuard默认是混淆全部代码的,但是这样经常会引起一些问题. 重点是混淆规则的编写,.总结起来就三条: 1   android

android 调用 screenrecord 实现录屏

首先要说明的是并未实现,本文讲一下自己的思路. adb 使用shell 命令 screenrecord 可录屏. 自己写了个app,通过Process p = Runtime.getRuntime().exec(cmd)的方式调用shell命令,报错: java.lang.SecurityException: Permission Denial: broadcast asks to run as user -2 but is calling from user 0 需要android.permi

Android实现录屏直播(一)ScreenRecorder的简单分析

应项目需求瞄准了Bilibili的录屏直播功能,基本就仿着做一个吧.研究后发现Bilibili是使用的MediaProjection 与 VirtualDisplay结合实现的,需要 Android 5.0 Lollipop API 21以上的系统才能使用. 其实官方提供的android-ScreenCapture这个Sample中已经有了MediaRecorder的实现与使用方式,还有使用MediaRecorder实现的录制屏幕到本地文件的Demo,从中我们都能了解这些API的使用. 而如果需

安卓实战开发之JNI入门及高效的配置(android studio一键生成.h,so及方法签名)

前言 以前也讲过NDK开发,但是开始是抱着好玩的感觉去开始的,然后呢会helloWord就觉得大大的满足,现在静下来想这NDK开发到底是干什么呢? NDK开发,其实是为了项目需要调用底层的一些C/C++的一些东西:另外就是为了效率更加高效些但是在java与C相互调用时平白又增大了开销(其实效率不见得有所提高),然后呢,基于安全性的考虑也是为了防止代码被反编译我们为了安全起见,使用C语言来编写这些重要的部分来增大系统的安全性,最后呢生成so库便于给人提供方便. 好了,我们来看一下qq的结构,我们就