前言

在上两篇文章中,我们已经学习了 CMake 和 Shell 的使用,接下来本篇文章开始对 ffmpeg 进行编译, 在编译开始之前 需要准备好 Linux 环境,下载 NDK,配置 NDK 环境变量等等,这在之前的两篇文章中都有,这里就不再展开介绍了

首先先下载好 ffmpeg,然后在解压在 Linux 中,就可以得到目录结果是这样的文件

首先观察这个文件,可以看到有一个 Makefile 文件,那么是不是意味着可以直接运行 make 指令开始编译了呢,运行后一下会得到如下这个结果

1
2
Makefile:206: /tests/Makefile: No such file or directory
make: *** No rule to make target '/tests/Makefile'.  Stop.

可以发现缺少了文件,这个文件怎么来呢,其实面对一个第三方库,有这么以下几个通用准则

  1. 阅读 README.md
  2. 编译项目(动静态库)需要 Makefile 管理,如果已经有写好的 Makefile 可以尝试着用 make 命令去编译,如果没有需要自己写 Makefile 或者采用 cmake 构建
  3. 如果报错需要解决,一般情况下都是 Makefile 的一些配置文件没生产,所以一般需要运行 configure 文件, 基本上很多库,都会有这个文件
  4. 生产配置文件之后,再次运行 make, 但是编译后的文件(elf,so,a)只能当前类型系统上运行
  5. 如果需要跑到 android 或者 iOS 那么需要交叉编译
  6. 因此我们一般都需要往 configure 文件里面传一些交叉编译参数

仔细看看这个库的话,其实提供了一个 configure 文件,一般我们运行 ./configure 文件就可以了,但是可能还有一些参数需要配置,所以运行 ./configure –help 根据自己的需要需要配置那些参数即可,现在我们直接编写一个 shell 脚本来进行编译

我这里的编译环境和版本如下

1
2
3
NDK r27
ffmpeg 7.0.2
Ubuntu 22.04.3 LTS Linux version 5.10.16.3-microsoft-standard-WSL2 (oe-user@oe-host) (x86_64-msft-linux-gcc (GCC) 9.3.0, GNU ld (GNU Binutils) 2.34.0.20200220) #1 SMP Fri Apr 2 22:23:49 UTC 2021

提前说一句,这里我使用的是 r27 的版本,一开始我编写的脚本是使用 gcc 进行编译的,死活都编译不过去,原因未知,后面排查说是,gcc 在 ndk 17 的时候就已经被移除了,所以后面又查看大量的文章看 clang 如何编译的,废了很多时间

同时,还需要修改 configure 文件中的几个配置

  1. 找到 CMDLINE_SET 新增加 cross_prefix_clang 参数

  1. 然后搜索 ar_default

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    将 
    ar_default="${cross_prefix}${ar_default}"
    cc_default="${cross_prefix}${cc_default}"
    cxx_default="${cross_prefix}${cxx_default}"
    nm_default="${cross_prefix}${nm_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}"
  2. 配置项目, 目的是生成一些必要的文件

    1
    
    ./configure --disable-x86asm

编写编译脚本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#!/bin/bash
set -x
# 目标Android版本
API=29
ARCH=arm64
CPU=armv8-a
TOOL_CPU_NAME=aarch64
#so库输出目录
OUTPUT=$(pwd)/android/$CPU
# NDK的路径,根据自己的NDK位置进行设置
NDK=$NDK_PATH
# 编译工具链路径
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64
# 用于配置交叉编译环境的路径
SYSROOT=$TOOLCHAIN/sysroot

TOOL_PREFIX="$TOOLCHAIN/bin/$TOOL_CPU_NAME-linux-android"

CC="$TOOL_PREFIX$API-clang"
CXX="$TOOL_PREFIX$API-clang++"
OPTIMIZE_CFLAGS="-march=$CPU"
function build
{
  ./configure \
  --prefix=$OUTPUT \
  --target-os=android \
  --arch=$ARCH  \
  --cpu=$CPU \
  --enable-gpl \
  --enable-small \
  --disable-programs \
  --disable-asm \
  --enable-neon \
  --enable-cross-compile \
  --enable-shared \
  --disable-static \
  --disable-doc \
  --disable-ffplay \
  --disable-ffprobe \
  --disable-symver \
  --disable-ffmpeg \
  --cc=$CC \
  --cxx=$CXX \
  --sysroot=$SYSROOT \
  --extra-cflags="-Os -fpic $OPTIMIZE_CFLAGS" \
  --disable-vulkan \
  --disable-stripping

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

执行 ./build.sh 后,就会得到如下的头文件和 so 库, 如果还想编译其他的 so 库,只需要重新赋值一下变量,然后再调用一下 build 就可以了

然后导入到 Android studio 中,添加我们引入的头文件和链接 SO 库

最后,再找个 cpp 中导入方法试试

可以看到正常输出了

参考 https://juejin.cn/post/6844904048303276045