Android录屏并利用FFmpeg转换成gif(二)
写博客时经常会希望用一段动画来演示app的行为,目前大多数的做法是在电脑上开模拟器,然后用gif录制软件录制模拟器屏幕,对于非开发人员来讲这种方式还是比较困难的。本来我以为应该也有能直接在手机上录屏并生成gif文件这样的app,下载一个这样的APP来录gif要方便得多。结果发现目前几乎没有此类APP,我就想能不能自己写一个,然后查了查资料,感觉应该能做出来,于是就撸起袖子干起来了。总的来讲要实现这个功能可以分成两个部分(当然,如果有更好的实现方式欢迎大家提出来,谢谢!):
- 录屏,生成mp4文件
- 利用ffmpeg开源软件将mp4转换成gif
第一点比较容易实现,已有现成的开源代码供参考。难点在第二点,涉及到NDK开发相关的知识,及FFmpeg的集成,这方面知识我之前从未接触过,还是比较有挑战性的。
功能虽然很简单,但要讲解起来感觉还是要费点篇幅的,所以我分成了4篇文章来介绍,分别是:
-
Android录屏并利用FFmpeg转换成gif(一) 录屏,讲讲怎样录屏生成mp4文件
-
Android录屏并利用FFmpeg转换成gif(二) 交叉编译FFmpeg源码,说说如何根据我们的需求裁剪FFmepg并编译出可在android下运行的so包
-
Android录屏并利用FFmpeg转换成gif(三) 在Android中使用ffmpeg命令,说说如何在Android中使用ffmpeg命令,简化C代码的编写难度
-
Android录屏并利用FFmpeg转换成gif(四) 将mp4文件转换成gif文件,将2、3两步生成的so文件集成到android工程中,实现将mp4文件转换成gif文件,完成最终的工程。
起程
为了将mp4文件转换成gif文件,我们选择了使用FFmpeg来实现。FFmpeg是一个开源的功能强大的音视频处理软件,我们在这里只用到了其中的一个很小的功能,由于移动设备上的资源比较紧张,所以有必要对FFmpeg做些裁剪,去掉一些我们用不上的功能,使其既能满足我们的功能需要又不会太占用资源。
另外,由于我们编译出来的FFmpeg是要在android上使用的,而我们是在电脑上编译的,这就涉及到交叉编译。
交叉编译
指在某个系统平台下产生可以在另一个系统平台运行的可执行文件的过程。所谓的系统平台具体是指cpu架构(相关的概念这里就不展开介绍了)。打个不太严谨的比方来说,你在windows下编译出来的一个exe文件,在windows系统下可以运行,但拿到linux系统下去就无法运行了,那么,如果在windows下编译出来一个可执行文件拿到linux系统下可以运行,但在windows下不能运行,这就叫交叉编译。而与之相对应的,在windows下编译出来的可执行文件,只能在windows系统下运行,就叫本地编译。
因此这篇文章主要就是介绍这两个方面的内容:
- 裁剪FFmpeg的功能
- 交叉编译FFmpeg
一、裁剪FFmpeg
先交待一下开发环境:
- 操作系统:Ubuntu 16.04 LTS
- FFmpeg源码:ffmpeg-3.4.1
- NDK版本:android-ndk-r15c
先看看最简单的情况,假设既不考虑交叉编译,也不考虑裁剪,要怎么编译FFmpeg呢?相信对linux稍有了解的人都会觉得很容易,进入FFmpeg源码根目录,然后运行configure脚本
~$ ./configure
再执行 make命令
~$ sudo make
最后安装
~$ sudo make install
就完成了。
当然实行执行过程中可以还可能需要安装依赖包,但基本流程是这样的,以上命令是按默认的配置进行编译的,包含了全部功能。如果要修改配置的话就要在运行configure命令时加上编译选项,如:
~$ ./configure --prefix=../build
–prefix=选项表示编译好的文件放在在哪里。而裁剪FFmpeg的功能也是在这里添加相应的选项,具体是什么选项先不管,现在只要知道在哪里进行配置就可以了。
所以接下来就要折腾这些个选项了,这里面选项特别多,可以用 --help参数查看一下帮助文档。由于选项太多了,而且有些选项我也不清楚是做什么的,这里只简单地介绍一下用到的几个选项:
- – --prefix=PREFIX 在PREFIX目录下安装FFmpeg,默认在/usr/local目录下
- – --disable-static 不要编译静态库,默认会编译静态库
- – --enable-shared 编译动态库,默认不会编译动态库
- – --disable-programs 不编译命令行应用程序,默认会编译命令行应用程序,如:ffmpeg,ffplay等
- – --disable-doc 不编译文档,默认会编译文档
- – --disable-encoders 禁用所有编码器,与下面的–enable-encoder=NAME配合可开放指定的编码器
- – --enable-encoder=NAME 开放指定的编码器,可以有多个
- – --disable-decoder=NAME 禁用所有解码器,与下面的–enable-decoder=NAME配合可开放指定的编码器
- – --enable-decoder=NAME 开放指定的解码器,可以有多个
- – --disable-muxers 禁用所有的复用器,与下面的–enable-muxer=NAME配合可开放指定的复用器
- – --enable-muxer=NAME 开放指定的复用器,可以有多个
- – --disable-demuxers 禁用所有的解复用器,与下面的–enable-demuxer=NAME配合可开放指定的解复用器
- – --enable-demuxer=NAME 开放指定的解复用器,可以有多个
- – --disable-parsers 禁用所有的解析器,与下面的–enable-parser=NAME配合可开放指定的解析器
- – --enable-parser=NAME 开放指定的解解析器, 可以有多个
FFmpeg所支持的所有编码器,解码器等可以用 --list-decoders
, --list-encoders
等参数来查看,非常多,一般是根据需要选择几种。
现在我们了解到要裁剪FFmpeg就是在执行configure脚本时设置一些参数,并了解了部分参数的意义,那么回到我们的需求上来,我们的目的是将mp4文件转换成gif,与这个功能不相关的东西都尽可能去掉。为什么说“尽可能”呢,因为我个人认为要精确地挑选出我们仅需要的那些组件并不是件容易的事,大多数情况都是在参考别人的基础上做些修改或补充,基本能达到要求就行了,这样做效率高点,代价是编译出来的so包并不是最精简的。针对我们现在的这个需求,有些组件是明显的不需要的,比如文档、命令行程序、静态库,这些可以先排除掉,至于编解码器等组件,先把所支持的相关组件列出来然后把带有“mp4”,“gif”,“jpeg”等字眼的组件都选上,然后编译出来,再试一下能不能把mp4文件转换成gif,如果不能就看看日志或上网查查资料看看是少了什么组件再补上,如果能实现我们要的功能则在原来的选项基础上做点删减,尽量排除掉我们不需要的功能。下面的脚本是我用以上方法敲定的最后方案,编译出来的so包总共约5M的样子。
#!/bin/bash
echo "###### 开始配置ffmpeg ######"
#配置configure文件,对ffmpeg进行裁剪
#裁剪目标:只需要将mp4转换成gif,其它能不要的就不要
#1 标准选项全部使用默认配置
#2 许可证选项暂时不要,使用默认
#3 配置选项,先disable all,再在程序选项/组件选项/库选项中enable自己想要的东西
#4 程序选项,只要ffmpeg
#5 文档选项,不需要
#6 组件选项,根据需要选择
#7 特定的组件选项, 根据需要选择
#8 外部库支持,默认
#9 工具链选项,默认
#10 高级选项,默认
#11 优化选项,默认
#12 开发者选项,默认
cd /home/hm/ffmpeg/ffmpeg_source/ffmpeg-3.4.1
./configure \
--prefix=/home/hm/ffmpeg/ffmpeg_linux/ffmpeg3.4.1 \
--disable-static \
--enable-shared \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-doc \
--disable-encoders \
--enable-encoder=mjpeg \
--enable-encoder=gif \
--disable-decoders \
--enable-decoder=mjpeg \
--enable-decoder=h264 \
--enable-decoder=mpeg4 \
--disable-muxers \
--enable-muxer=gif \
--enable-muxer=mjpeg \
--enable-muxer=image2 \
--disable-demuxers \
--enable-demuxer=mpegvideo \
--enable-demuxer=image2 \
--enable-demuxer=mjpeg \
--enable-demuxer=h264 \
--enable-demuxer=mov \
--disable-parsers \
--enable-parser=mjpeg \
--enable-parser=mpegvideo \
--enable-parser=h264 \
--extra-cflags=-fPIC
echo "###### ffmpeg配置完成,开始 make ######"
注意:
以上脚本是本地编译脚本,目的是裁剪FFmpeg,编译出来的so包并不能在android上运行,只能在电脑上运行,保留ffmpeg命令行程序是为了在电脑上测试编译出来的so包能不能将mp4转换成gif,移植到android时是不需要命令行程序的。
二、交叉编译FFmpeg
跟前面一样,假设我们只考虑交叉编译,不管裁剪等因素,那么要怎么做呢?实际上还是在执行configure脚本时加上编译选项,具体添加什么选项我们等下再说。
在执行configure脚本之前我们要先对configure文件作点修改。由于Android 工程中只支持导入 .so 结尾的动态库,形如:libavcodec-57.so 。但是FFmpeg 编译生成的动态库默认格式为 xx.so.版本号 ,形如:libavcodec.so.57 , 所以需要修改 FFmpeg 根目录下的 configure 文件,使其生成以 .so 结尾格式的动态库:
# 将 configure 文件中的:
SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)'
SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR) $(SLIBNAME)'
#替换为:
SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'
SLIB_INSTALL_LINKS='$(SLIBNAME)'
好,下面来讲跟交叉有关的编译选项,跟交叉有关的编译选项主要有以下几个:
- – --enable-cross-compile 允许交叉编译,默认不允许
- – --cross-prefix= 指定编译工具的前缀,默认不指定。例如:-- --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- 表示所有用到的编译工具都是在 bin 目录下以 arm-linux-androideabi- 开头的相对应的工具,比如要用到c编译器的时候就使用bin目录下的arm-linux-androideabi-gcc工具来编译,gcc是默认的c编译器名字,arm-linux-androideabi-是前缀,其它工具也是类似。这是一种类似通配符的写法,这样可以不用一个个去指定所需要的编译工具。
- – --target-os=OS 编译目标操作系统,我们的目标是android系统,使用linux内核,要指定为linux
- – --arch=ARCH 目标cpu架构
- – --sysroot=PATH 指定编译过程中需要引用的库,头文件所在的逻辑目录。比如编译器通常会在 /usr/include 和 /usr/lib 中搜索头文件和库,如果指定了sysroot选项则会去$PATH/usr/include 和 $PATH/usr/lib 目录中搜索。
指定好这些参数就可进行交叉编译了,下面是一个交叉编译的例子:
#!/bin/bash
echo "###### 开始配置ffmpeg_android 包含全部编解码器 ######"
NDK=/home/hm/android-ndk-r14b
SYSROOT=$NDK/platforms/android-15/arch-arm/
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
CPU=arm
PREFIX=/home/hm/ffmpeg/ffmpeg_android/builder333
cd /home/hm/ffmpeg/ffmpeg_source/FFmpeg-n3.3.3
./configure \
--prefix=$PREFIX \
--enable-cross-compile \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--target-os=linux \
--arch=arm \
--sysroot=$SYSROOT \
--enable-shared \
--disable-static \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver\
--extra-cflags="-Os -fpic "
echo "###### ffmpeg_android配置完成,开始 make ######"
三、大团圆
现在裁剪跟交叉编译都知道怎么弄了,把它们合起来就可以编译出我们要的so包了,下面是综合后的脚本:
#!/bin/bash
echo "###### 开始配置ffmpeg_android 经过裁剪的编解码器 ######"
echo "###### 编译环境:NDK-r15c,ffmpeg3.4.1 ######"
NDK=/home/hm/android-ndk-r15c
#注意,android-ndk-r15c环境下,SYSROOT路径要选android-21以上平台
SYSROOT=$NDK/platforms/android-21/arch-arm/
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
CPU=arm
PREFIX=/home/hm/ffmpeg/ffmpeg_android/builder4
cd /home/hm/ffmpeg/ffmpeg_source/ffmpeg-3.4.1
./configure \
--prefix=$PREFIX \
--enable-cross-compile \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--target-os=linux \
--arch=arm \
--sysroot=$SYSROOT \
--enable-shared \
--disable-static \
--disable-doc \
--disable-programs \
--disable-encoders \
--enable-encoder=mjpeg \
--enable-encoder=gif \
--disable-decoders \
--enable-decoder=mjpeg \
--enable-decoder=h264 \
--enable-decoder=mpeg4 \
--disable-muxers \
--enable-muxer=gif \
--enable-muxer=mjpeg \
--enable-muxer=image2 \
--disable-demuxers \
--enable-demuxer=mpegvideo \
--enable-demuxer=image2 \
--enable-demuxer=mjpeg \
--enable-demuxer=h264 \
--enable-demuxer=mov \
--disable-parsers \
--enable-parser=mjpeg \
--enable-parser=mpegvideo \
--enable-parser=h264 \
--extra-cflags="-Os -fpic "
echo "###### ffmpeg_android配置完成,开始 make ######"
make clean
make -j4
make install
执行完上面的脚本后,就会在/home/hm/ffmpeg/ffmpeg_android/builder4目录下生成我们想要的so包,如下:
其中的
7个包就是我们要拷到android工程中的包。不过要验证这些包能否实现我们的功能就不像在本地编译时那么方便了,可以参考下一篇Android录屏并利用FFmpeg转换成gif(三) 在Android中使用ffmpeg命令,但由于我们之前已经在pc上验证了裁剪部分的功能,所以把握性还是比较大的。
###最后,上源码:
源码的话就只有一个脚本了,NDK,FFmpge源码自己到网上去下,注意版本。
本文用到的版本:
NDK:https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip (点击下载)
FFmpeg:http://ffmpeg.org/releases/ffmpeg-3.4.1.tar.bz2 (点击下载)
脚本:https://github.com/MingHuang1024/CrossCompileForFFmpeg
由于水平有限,如果文中存在错误之处,请大家批评指正,欢迎大家一起来分享、探讨!
博客:http://blog.csdn.net/MingHuang2017
GitHub:https://github.com/MingHuang1024
Email:minghuang1024@foxmail.com
微信:724360018