【Android 音视频开发打怪升级:FFmpeg音视频编解码篇】一、FFmpeg so库编译

【Android 音视频开发打怪升级:FFmpeg音视频编解码篇】一、FFmpeg so库编译_第1张图片

【声 明】

首先,这一系列文章均基于自己的理解和实践,可能有不对的地方,欢迎大家指正。
其次,这是一个入门系列,涉及的知识也仅限于够用,深入的知识网上也有许许多多的博文供大家学习了。
最后,写文章过程中,会借鉴参考其他人分享的文章,会在文章最后列出,感谢这些作者的分享。

码字不易,转载请注明出处!

教程代码:【Github传送门】

目录

一、Android音视频硬解码篇:

  • 1,音视频基础知识
  • 2,音视频硬解码流程:封装基础解码框架
  • 3,音视频播放:音视频同步
  • 4,音视频解封和封装:生成一个MP4

二、使用OpenGL渲染视频画面篇

  • 1,初步了解OpenGL ES
  • 2,使用OpenGL渲染视频画面
  • 3,OpenGL渲染多视频,实现画中画
  • 4,深入了解OpenGL之EGL
  • 5,OpenGL FBO数据缓冲区
  • 6,Android音视频硬编码:生成一个MP4

三、Android FFmpeg音视频解码篇

  • 1,FFmpeg so库编译
  • 2,Android 引入FFmpeg
  • 3,Android FFmpeg视频解码播放
  • 4,Android FFmpeg+OpenSL ES音频解码播放
  • 5,Android FFmpeg+OpenGL ES播放视频
  • 6,Android FFmpeg简单合成MP4:视屏解封与重新封装
  • 7,Android FFmpeg视频编码

本文你可以了解到

使用 GCCCLANG 交叉编译出Android平台可以使用的FFmpeg so库。为了很好的迈出 FFmpeg 开发的第一步,不仅要知其然,更要知其所以然。不仅要知道怎么样能成功编译,更要知道为什么能成功编译。在开始动手之前,建议先通读整篇文章,相信本文定可以让你有所感悟。

一、前言

网上其实已经有很多的关于FFmpeg so库编译的分享,但是大部分都是直接把配置文件的内容贴出来。我想大部分取搜索 「如何编译FFmpeg so库」的人,对交叉编译这个东东都是比较陌生的。

特别对于移动端开发者来说,大部分人大多数时候都是在Java层做开发,很少接触到NDK层的东西。如果直接去看一份交叉编译的配置,估计会很上头。

通常情况下,在一篇FFmpeg编译的文章下面都会有很多的类似「为什么按照楼主的配置还是无法编译成功?」的评论,那为什么人家可以编译成功,我们copy下来却不可以呢?

原因有非常多,大部分其实集中在以下几个方面:

1. 无脑copy,祈求有一个傻瓜式的配置可以成功编译;
2. FFmpeg版本和NDK版本很多,每一个版本都可能需要不一样的配置;
3. 不了解每个配置项的意义,即使好运配置对了, 但是稍微一修改,又无法正常编译了。

为什么FFmpeg让人觉得很难搞?

我想主要是因为迈出第一步就很困难,连so库都编译不出来,后面的都是扯淡了。

二、什么是交叉编译

定义

引自百度百科的定义:交叉编译,是在一个平台上生成另一个平台上的可执行代码。

什么意思呢?说白了,就是在一个机器上生成一个程序,这个程序可以跑在另外一个机器上。举栗:在PC上编译一个apk,这个apk可以跑在Android手机上,这其实就是一个交叉编译的过程。

为什么要交叉编译

我们知道,PC上的软件是直接在PC上编译生成的,那为什么Android上的软件不能在Android上自己编译生成呢?

理论上是可以,但是Android手机上的资源有限啊,在PC上编译一个apk都要那么久,你可以想象在Android手机上编译一个apk要多久吗?或者你能想象在手机上敲代码的情景吗?

那我们会想既然PC上资源那么丰富,那可不可以利用PC来编译出在手机上可以运行的软件呢?

于是,交叉编译出现。

交叉编译需要的什么

编译环境

我们知道PC上的环境和手机上的运行环境是绝然不同的,如果使用PC上的环境直接编译的话,可以想象这个编译出来的App,分分钟就会挂掉。

所以,交叉编译最重要的是,要配置好编译过程中使用到的相关的环境,而这个环境其实就是目标机器(比如Android手机)正在运行的环境。

编译工具链

对于C/C++的编译,通常有两个工具 GCCCLANG

GCC 可能大家都有听说过,这是一个老牌的编译工具,不仅可以编译C/C++,也可以编译Java,Object-C,Go等语言。

CLANG 则是一个效率更高的C/C++编译工具,并且兼容GCC,Google在很早以前就开始建议使用clang进行编译,并且在 ndk 17 以后,把 GCC 移除了,全面推行使用 CLANG

三、如何交叉编译FFmpeg

FFmpeg是什么

鼎鼎大名的FFmpeg,不说在音视频界如雷贯耳,就算一个不开发音视频的开发者也都是略有耳闻。

官方简介

A complete, cross-platform solution to record, convert and stream audio and video.

翻译过来就是:FFmpeg是一套集录制、转换以及流化音视频的完整的跨平台解决方案。

从这段简介可以看到FFmpeg有以下特点:

  1. 功能强大:录制、解码、编码、编辑、推流等等
  2. 跨平台

编译流程

从前面的介绍,基本上可以总结出FFmepg编译的基本流程:

  1. 选择编译工具
  2. 配置交叉编译环境
  3. 配置编译参数(比如去掉一些不需要的功能)
  4. 启动编译

流程就是这么简单,接下来就来详细看看,如何通过 CLANGGCC 两种方式来编译。

四、使用CLANG编译FFmpeg

注:本文编译平台为Mac,建议使用Mac或者Linux进行编译,据说Windows有很多坑。

下载Android NDK

Android 的 NDK 已经迭代了很多版本,在 r17c 以后,Google正式移除 GCC ,不再支持 GCC ,新版本的 NDK 都是使用 CLANG 进行编译。

这里就使用目前最新的 NDK r20b 版本来编译。

NDK 下载地址:Android-NDK

NDK 目录
【Android 音视频开发打怪升级:FFmpeg音视频编解码篇】一、FFmpeg so库编译_第2张图片
NDK r20b 目录

最主要的就是这两个路径:

编译工具链目录:
toolchains/llvm/prebuilt/darwin-x86_64/bin

交叉编译环境目录:
toolchains/llvm/prebuilt/darwin-x86_64/sysroot
  • 编译工具路径
【Android 音视频开发打怪升级:FFmpeg音视频编解码篇】一、FFmpeg so库编译_第3张图片
编译工具

根据不同的CPU架构区和不同的Android版本,区分了不同的clang工具,根据自己需要选择就好了。

本文选择 CPU 架构 armv7a,Android版本 21:

armv7a-linux-androideabi21-clang
armv7a-linux-androideabi21-clang++
  • 编译环境路径

toolchains/llvm/prebuilt/darwin-x86_64/sysroot 目录下,包含了两个目录: usr/includeusr/lib,分别对应了 头文件库文件

【Android 音视频开发打怪升级:FFmpeg音视频编解码篇】一、FFmpeg so库编译_第4张图片
库文件和头文件

下载FFmpeg源码

FFmpeg官网下载,直接DownLoad即可。

本文使用的是目前最新的版本 ffmpeg-4.2.2

下载好源码后,进入根目录,找到一个名为 congfigure 的文件,这是一个shell脚本,用于生成一些 FFmpeg 编译需要的配置文件。

这个文件非常重要,FFmpeg 的编译配置就是靠它完成的。
后面我们将对其中一些重要的内容进行分析,这是理解 FFmpeg 编译配置的关键。

有了以上基础以后,就可以对FFmpeg进行编译了。

配置脚本

  • 修改 configure 脚本
  1. 新增 cross_prefix_clang 参数

打开(注:不是双击运行) ffmpeg-4.2.2 根目录下的 configure 文件,搜索 CMDLINE_SET ,可以找到以下代码,然后新增一个命令行选项:cross_prefix_clang

CMDLINE_SET="
    $PATHS_LIST
    ar
    arch
    as
    assert_level
    build_suffix
    cc
    objcc
    cpu
    cross_prefix
    # 新增命令行参数
    cross_prefix_clang
    custom_allocator
    cxx
    dep_cc
    # 省略其他.....
"
  1. 修改编译工具路径设置

搜索 ar_default="${cross_prefix}${ar_default}" , 找到以下代码

ar_default="${cross_prefix}${ar_default}"
cc_default="${cross_prefix}${cc_default}"
cxx_default="${cross_prefix}${cxx_default}"
nm_default="${cross_prefix}${nm_default}"
pkg_config_default="${cross_prefix}${pkg_config_default}"

将中间两行修改为

ar_default="${cross_prefix}${ar_default}"
#------------------------------------------------
cc_default="${cross_prefix_clang}${cc_default}"
cxx_default="${cross_prefix_clang}${cxx_default}"
#------------------------------------------------
nm_default="${cross_prefix}${nm_default}"
pkg_config_default="${cross_prefix}${pkg_config_default}"

至于为什么这么修改,将在后面的 configure 分析中详细讲解

  • 新建编译配置脚本

ffmpeg-4.2.2 根目录下新建 shell 脚本,命名为: build_android_clang.sh

#!/bin/bash
set -x
# 目标Android版本
API=21
CPU=armv7-a
#so库输出目录
OUTPUT=/Users/cxp/Desktop/FFmpeg/ffmpeg-4.2.2/android/$CPU
# NDK的路径,根据自己的NDK位置进行设置
NDK=/Users/cxp/Desktop/FFmpeg/android-ndk-r20b
# 编译工具链路径
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/darwin-x86_64
# 编译环境
SYSROOT=$TOOLCHAIN/sysroot

function build
{
  ./configure \
  --prefix=$OUTPUT \
  --target-os=android \
  --arch=arm \
  --cpu=armv7-a \
  --enable-asm \
  --enable-neon \
  --enable-cross-compile \
  --enable-shared \
  --disable-static \
  --disable-doc \
  --disable-ffplay \
  --disable-ffprobe \
  --disable-symver \
  --disable-ffmpeg \
  --sysroot=$SYSROOT \
  --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
  --cross-prefix-clang=$TOOLCHAIN/bin/armv7a-linux-androideabi$API- \
  --extra-cflags="-fPIC"

  make clean all
  # 这里是定义用几个CPU编译
  make -j12
  make install
}

build

这个shell脚本,大体上其实还是很容易懂的,比如

--disabble-static --enable-shared 分别用于禁止输出静态库,以及输出动态库;

--arch --cpu 用于配置输出的so库是什么架构的;

--prefix 用于配置输出的so库的存放路径。

接下来重点来讲一下几个选项:

  • target-os

--target-os=android:在旧版本的 FFmpeg 中,对Android平台的支持并不是很完善,并没有 android 这个target,所以在一些比较老的文章中都会提到,编译Android平台的so库,需要对 configure 做以下修改,否则会按照 linux 标准的方式输出so库,其命名方式和Android的so不一样,Android是无法加载的。

SLIBNAME_WITH_VERSION='$(SLIBNAME).$(LIBVERSION)'
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_VERSION='$(SLIBNAME).$(LIBVERSION)'
SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'  
LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'  
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'  
SLIB_INSTALL_LINKS='$(SLIBNAME)'

但是在新版本的FFmpeg中,这个问题终于被解决了,FFmpeg加入了 android 这个 target所以我们再也不需要手动去修改了

  • sysroot

--sysroot=$SYSROOT: 用于配置交叉编译环境的 根路径 ,编译的时候会默认从这个路径下去寻找 usr/include usr/lib 这两个路径,进而找到相关的头文件和库文件。

r20b 版本的 NDK 系统的头文件和库文件就是在 $SYSYROOT/usr/include$SYSYROOT/usr/lib 中。

基本上很多新手在编译的时候都会出现找不到各种头文件,导致编译失败。所以当编译出现找不到头文件的时候,首先要检查的就是这个路径。

一点疑问

在使用最新的 ndk r20b 版本进行编译的时候发现,即使不配置 sysroot 也可以正常编译,怀疑 Android 的 clang 工具是否经过了处理,会自动去寻找对应的路径。 目前没有从 configure 文件中找到原因。
如有知情者的,还望告知呀~。

说到 sysroot 就不得不提到另外一个参数 -isysyroot ,这个参数也让我困惑了很久,因为很少文章会提到这个两个参数的联系和区别,然而这个参数也很导致让人很莫名奇妙的编译失败。

  • extra-cflags

介绍 -isysroot 之前,先看看这个 extra-cflags 选项。

这个选项的作用是,给编译器指定除了 sysroot 之外的头文件搜索路径。比如:

--extra-cflags="-I$SYSROOT/usr/include"

# 其中 -I 用于区分不同的路径

-isysroot 是这个选项的一个配置。比如

--extra-cflags="-isysroot $SYSROOT"

-isysroot 的作用就是,把后面的路径设置为默认的头文件搜索路径,这时候,前面 sysroot 配置路径就不再作为 头文件 默认的搜索路径了,不过依然是 库文件 默认的搜索路径。

可以看到,这两个配置从某种程度上说是一样的:

--extra-cflags="-I$SYSROOT/usr/include"

约等于

--extra-cflags="-isysroot $SYSROOT"

  • extra-ldflags

这个和上面的 extra-cflags 作用是类似的,不过是用于配置额外的 库文件 搜索路径,如

--extra-ldflags="-L$SYSROOT/usr/lib"
# 其中 -L 用于区分不同的路径

可以看到 extra-cflags extra-ldflags 结合起来可以替代 sysroot

  • cross-prefix

这个选项直译为 交叉编译前缀,指的是交叉编译工具的前缀。

这个选项经常和另外一个选项 cc 一起出现搭配使用。

这是什么意思呢?网上有的文章对于 cc 这个选项经常出现两种配置方式:

一种是只配置 cross-prefix ,没有配置 cc ,比如本文。

另一种是既配置 cross-prefix ,又配置 cc

比如:

--cc=$TOOLCHAIN/bin/arm-linux-androideabi-gcc \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \

这是两种完全不同的配置方式,但是很神奇的是有时候他们都能成功编译,有时候又会出现找不到编译链工具的错误。

为了搞明白 cross-prefix cc 这两个选项的配置到底有什么影响,到底应该怎么使用这两个配置,我特地仔细的去看了 FFmpeg 根目录下的 configure 配置脚本,找到了一些蛛丝马迹。

分析 configure 配置脚本

注:以下分析基于ffmpeg-4.2.2版本,其他版本可能有所不同,掌握基本原理即可。

  • 获取用户配置选项

打开(注:不是双击运行)configure shell脚本,首先来看看 configure 是如何获取用户配置的编译选项的。

搜索 for opt do,可以找到以下代码

for opt do
    optval="${opt#*=}"
    case "$opt" in
        --extra-ldflags=*)
            add_ldflags $optval
        ;;
        --extra-ldexeflags=*)
            add_ldexeflags $optval
        ;;
        --extra-ldsoflags=*)
            add_ldsoflags $optval
        ;;
        --extra-ldlibflags=*)
            warn "The --extra-ldlibflags option is only provided for compatibility and will be\n"\
                 "removed in the future. Use --extra-ldsoflags instead."
            add_ldsoflags $optval
        ;;
        --extra-libs=*)
            add_extralibs $optval
        ;;
        --disable-devices)
            disable $INDEV_LIST $OUTDEV_LIST
        ;;
        --enable-debug=*)
            debuglevel="$optval"
        ;;
        
        # 省略中间一些代码...
        
        *)
            optname="${opt%%=*}"
            optname="${optname#--}"
            optname=$(echo "$optname" | sed 's/-/_/g')
            if is_in $optname $CMDLINE_SET; then
                eval $optname='$optval'
            elif is_in $optname $CMDLINE_APPEND; then
                append $optname "$optval"
            else
                die_unknown $opt
            fi
        ;;
    esac
done

这个shell脚本的代码有很多特有的语法,也不用钻牛角尖,能大概看明白就可以了。

for循环的首行 通过分割 = 获取到用户设置的选项值 optval

下面除了一些特殊的选项,我们看看最后的通配符 *) ,这段代码的目的,其实就是把用户配置的选项和值关联起来。

比如 --cpu=armv7-a ,前面三行就是把 cpu 分割出来,赋值给 optname,再把 optval 赋值给 cpu,说白了就是初始化了 cpu 这个变量为 armv7-a

  • Android相关的配置

搜索 android 关键字,可以找到以下代码

# ffmpeg-4.2.2/configure

if test "$target_os" = android; then
    cc_default="clang"
fi

ar_default="${cross_prefix}${ar_default}"
cc_default="${cross_prefix}${cc_default}"
cxx_default="${cross_prefix}${cxx_default}"
nm_default="${cross_prefix}${nm_default}"
pkg_config_default="${cross_prefix}${pkg_config_default}"

当你配置了 --target-os=android 的时候,FFmpeg默认的编译工具为 clang

cc_default 其实就是配置项 cc 的默认值,可以看到 cc_default 在这里和 cross_prefix 做了拼接。这里就是为什么说 cross_prefix 是交叉编译工具前缀。

拼接完是这样的:

cc_defalut=$TOOLCHAIN/bin/arm-linux-androideabi-$cc

看下 ar_default cc_default cxx_default这些默认值是什么。

搜索 cc_default 可以找到以下代码

# ffmpeg-4.2.2/configure

ar_default="ar"
cc_default="gcc"
cxx_default="g++"
host_cc_default="gcc"

可以看到,FFmpeg 默认的编译工具是 GCC

当你编译 Android 平台的库时,由于 configure 强制设置 cc_default="clang",所以:

  1. 当你使用 GCC 作为编译工具时,必须配置 cc 选项,或修改 configure 中的 cc_default="clang"cc_default="gcc" ;

  2. 当你使用 CLANG 作为编译工具时,可以不配置 cc 选项。

仔细想想会发现,为什么当 cc 配置为下边的值时,也可以正常编译呢?

--cc=$TOOLCHAIN/bin/arm-linux-androideabi-gcc

这时 cc_defalut 不就等于

cc_defalut=$TOOLCHAIN/bin/arm-linux-androideabi-$TOOLCHAIN/bin/arm-linux-androideabi-gcc

这个路径肯定是错的啊!

这就要来看到底 cc_default 是怎么使用的了。

  • 初始化变量

搜索 set_default arch ,可以看到以下代码,在这里 configure 重新设置了 cc 的默认值。

set_default arch cc cxx doxygen pkg_config ranlib strip sysinclude \
    target_exec x86asmexe nvcc

这里调用了一个叫 set_default 的函数,来看看这个函数的实现

set_default(){
    for opt; do
        eval : \${$opt:=\$${opt}_default}
    done
}

这也是一个看不太懂的shell语法,大概的意思就是:for循环获取所有的输入参数变量,然后给这个变量赋值。

比如 set_default cc ,意思就是 cc=cc_default ,不过有一点要注意的是中间这个符号 :=

这个符号类似Java中的三目运算符:

opt != null? opt:opt_defalut

也就是说,如果参数为空,将 xx_default 赋值给 xx

这就可以解释上面的疑问了。

  1. 当配置
--cc=$TOOLCHAIN/bin/arm-linux-androideabi-gcc

set_default cc 等于没有用了。因为经过 for 循环获取了用户的配置以后, cc 不为空。 set_default 后,cc 的值是不会改变的。

  1. cc 不配置的时候,FFmpeg 根据默认的拼接方式,把拼接好的路径设置给 cc

  2. 但是,不能配置 cc=gcc 这种,这样,最后 cc 的值就只有 gcc ,肯定是不能正确找到编译工具的。

  • 为什么要加入 corss-prefix-clang 这个选项

现在可以来解释为什么前面需要修改 configure 配置脚本了。

原始的配置是这样的

ar_default="${cross_prefix}${ar_default}"
cc_default="${cross_prefix}${cc_default}"
cxx_default="${cross_prefix}${cxx_default}"
nm_default="${cross_prefix}${nm_default}"
pkg_config_default="${cross_prefix}${pkg_config_default}"

也就是说,默认的 cc ar nm 路径前缀是一样的,但是 Android NDK 的路径却是这样的

【Android 音视频开发打怪升级:FFmpeg音视频编解码篇】一、FFmpeg so库编译_第5张图片
NDK clang路径

看到了不?ar/nmcc的前缀是不一样的,前者是 arm-linux-androideabi- , 后者是 armv7a-linux-androideabi16-

因此,需要对 cccxx 两个前缀进行修改,为此新加了 cross_prefix_clange 来进行单独配置。

这里只是针对 NDK r20b 的情况,不同的 NDK 版本可能有所不同,根据这个原理去设置即可。

综上,解释了一些编译 FFmpeg 常用的配置选项,并且从原理上弄明白为何要这样配置,基本上搞清楚了这些,想要组合两个不同版本的FFmpeg和NDK来编译,都会比较容易实现。

启动编译

打开cmd终端,cd 到 FFmpeg 所在目录

输入 ./build_android_clang.sh

等待编译完成,将会在 ffmpeg/android/armv7-a目录下得到 includelib 两个目录,分别是 头文件so库文件

【Android 音视频开发打怪升级:FFmpeg音视频编解码篇】一、FFmpeg so库编译_第6张图片
生成的so
【Android 音视频开发打怪升级:FFmpeg音视频编解码篇】一、FFmpeg so库编译_第7张图片
生成的头文件

五、使用 GCC 编译FFmpeg

目前大部分网上的文章都是使用 GCC 来编译 FFmpeg 的,下面就来看看如何配置 GCC 的编译参数。

下载 Android NDK r17b

前面就说过,NDK r17c 以后,Googole 就移除了 GCC,所以要使用 GCC 只能下载 r17c 及以前的版本,本文使用 r17c 来编译。

根据自己编译平台选择对应的版本:NDK r17c

本文选择的是 Mac 版本:Mac OS X。

NDK 相关的环境路径

【Android 音视频开发打怪升级:FFmpeg音视频编解码篇】一、FFmpeg so库编译_第8张图片
NDK r17c 目录

NDK r20b 相比,NDK r17c的目录稍微有些变化。

  • 交叉编译环境路径
# 库文件路径
android-ndk-r17c/platforms/android-21/arch-arm/usr/lib
# 头文件路径
android-ndk-r17c/sysroot/usr/include
  • GCC 工具链路径
android-ndk-r17c/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin

可以看到,Google 将 头文件库文件 分离了,这也是很多新手在编译的时候一直没有配对路径,导致编译失败的原因。

新建编译配置脚本

FFmpeg 的版本依然是使用上面的 ffmpeg-4.2.2 , 当然,这次不需要修改 configure 了。

根据前面介绍的知识,很容易就能写出编译配置了

ffmpeg-4.2.2 根目录新建脚本: build_android_gcc.sh

#!/bin/bash
set -x
API=21
CPU=armv7-a
#so库输出目录
OUTPUT=/Users/cxp/Desktop/FFmpeg/ffmpeg-4.2.2/android/$CPU
# NDK的路径,根据自己的安装位置进行设置
NDK=/Users/cxp/Desktop/FFmpeg/android-ndk-r17c
# 库文件
SYSROOT=$NDK/platforms/android-$API/arch-arm
# 头文件
ISYSROOT=$NDK/sysroot/usr/include
# 汇编头文件
ASM=$ISYSROOT/arm-linux-androideabi
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64

function build
{
./configure \
  --prefix=$OUTPUT \
  --target-os=android \
  --arch=arm \
  --cpu=armv7-a \
  --enable-asm \
  --enable-cross-compile \
  --enable-shared \
  --disable-static \
  --disable-doc \
  --disable-ffplay \
  --disable-ffprobe \
  --disable-symver \
  --disable-ffmpeg \
  --sysroot=$SYSROOT \
  --cc=$TOOLCHAIN/bin/arm-linux-androideabi-gcc \
  --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
  --extra-cflags="-I$ISYSROOT -I$ASM -fPIC"

make clean all
# 这里是定义用几个CPU编译
make -j12
make
make install
}
build

可以看到,在基本上配置和使用 CLANG 进行编译差不多。

有以下不同:

  1. 多了 cc 配置。因为如果不配置 cc 默认为 clang (参考前文的分析);
  2. 多了 extra-cflags 的配置,因为 SYSROOT 中只包含了 库文件 ,需要额外配置 头文件 的搜索路径;汇编头文件 的路径也不在 SYSROOT 中,也需要额外配置 ASM

启动编译

打开 cmd 终端,cd 到 ffmpeg-4.2.2 目录

执行 ./build_android_gcc.sh

六、总结

通过对 configure 的分析,可以让我们更加清晰的理解每个参数配置项的意义,以及如何搭配使用这些配置。只要清楚了各个配置的含义,无论版本怎么变化,都可很快的写出编译脚本。

当了,本文只是介绍了最基础的配置方案,你还可以通过更多的 --disable-xxx 选项实现对 FFmpeg 的裁剪,或者通过 --enable-xxx 选项,开启一些高级功能。

参考文章

FFmpeg源代码简单分析:configure
编译 FFmpeg 之 clang

你可能感兴趣的:(【Android 音视频开发打怪升级:FFmpeg音视频编解码篇】一、FFmpeg so库编译)