FFmpeg 7.1.1 | 编译 Android 动态链接库

时光飞逝,距离 《NDK 是什么 | FFmpeg 5.0 编译 so 库》 一文已经过去快三年了,曾经最新的 FFmpeg 5.0 ,如今也来到了 FFmpeg 7.1.1。本文就来通过 NDK 编译一下 Android 的 ffmpeg 动态链接库。关于 NDK 是什么可以详见上篇文章,这里不再赘述。


1. 准备编译环境

如果把 ffmpeg 源码编译动态链接库视为一道菜,那么:

厨房 : 我用的是 Windows 的 Linux 子系统 WSL2

厨具 : 用的 ndk 版本为 26.1.10909125

食材 : 在 https://www.ffmpeg.org/download.html 下载源码


2. 开始烹饪

首先将源码压缩包通过命令解压:

tar -xvf ffmpeg-7.1.1.tar.xz


然后进入 ffmpeg-7.1.1 目录,创建 build_android.sh 编译脚本。这里只编译了 arm64 的架构

cd ffmpeg-7.1.1

vim build_android.sh

bash 复制代码
#!/bin/bash

# 配置路径
NDK_PATH=/home/toly/SDK/AndroidSdk/ndk/26.1.10909125
TOOLCHAIN=$NDK_PATH/toolchains/llvm/prebuilt/linux-x86_64  # 根据系统调整

# 配置编译器
API_LEVEL=24
TARGET=aarch64-linux-android
CC=$TOOLCHAIN/bin/${TARGET}${API_LEVEL}-clang
CXX=$TOOLCHAIN/bin/${TARGET}${API_LEVEL}-clang++

# 设置 arm64 编译参数
ARCH=arm64  # 可选:arm, arm64, x86, x86_64
OUTPUT_DIR=$(pwd)/android/$ARCH
CPU=armv8-a


# 执行 FFmpeg 配置
./configure \
  --target-os=android \
  --prefix=$OUTPUT_DIR \
  --arch=aarch64 \
  --cpu=$CPU \
  --cc=$CC \
  --cxx=$CXX \
  --strip=$TOOLCHAIN/bin/llvm-strip \
  --enable-cross-compile \
  --sysroot=$TOOLCHAIN/sysroot \
  --enable-shared \
  --disable-static \
  --disable-doc \
  --disable-programs \
  --disable-avdevice \
  --disable-avfilter \
  --disable-postproc \
  --disable-symver \
  --extra-cflags="-O3 -fPIC"

# 清理并编译
make clean
make -j$(nproc)
make install

最后,给 build_android.sh 脚本可执行权限,运行即可。完成后,在 android 文件夹下会有我们需要的头文件和 so 链接库文件:

bash 复制代码
chmod +x build_android.sh
./build_android.sh

3. 盛菜上桌

接下来,创建一个 Native C++ 的 Android 项目,验证编译的结果是否正确。

把生面产出的文件,放下项目的对应位置。由于只打包了 arm64 , 可以在 app/build.gradle 中的 defaultConfig 里指定 ndk 支持的架构:

把默认的 hello 字符串改为 av_version_info 可以查看 FFmpeg 版本号; avcodec_configuration 可以查看编译时的配置信息:

c++ 复制代码
#include <jni.h>
#include <string>
extern "C"{
#include <libavcodec/avcodec.h>
}
extern "C" JNIEXPORT jstring JNICALL
Java_com_toly1994_toly_1ffmpeg_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    
//    return env->NewStringUTF( av_version_info()); // 查看版本号
    return env->NewStringUTF(avcodec_configuration()); // 查看编译配置信息
}
版本 编译信息

另外,CMakeLists.txt 中的内容和上一篇一样; 《Android NDK 开发 | CMake 使用手册 - 初见篇》 一文介绍过 CMake 的使用,后续有空会继续补充。

cmake 复制代码
cmake_minimum_required(VERSION 3.22.1)

project("toly_ffmpeg")

#引入头文件
include_directories(includes)

# 定义当前 so 库 - 在 java 代码中加载
add_library(toly_ffmpeg SHARED native-lib.cpp)

# 添加 ffmpeg 的 avcodec、swresample、avutil 模块 start======
set(ABI_DIR ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})

add_library(avcodec SHARED IMPORTED)
set_target_properties(avcodec PROPERTIES IMPORTED_LOCATION ${ABI_DIR}/libavcodec.so)

add_library(swresample SHARED IMPORTED)
set_target_properties(swresample PROPERTIES IMPORTED_LOCATION ${ABI_DIR}/libswresample.so)

add_library(avutil SHARED IMPORTED)
set_target_properties(avutil PROPERTIES IMPORTED_LOCATION ${ABI_DIR}/libavutil.so)
# 添加 ffmpeg 的 avcodec、swresample、avutil 模块 end======

find_library(log-lib log)
target_link_libraries(
        toly_ffmpeg
        avcodec
        swresample
        avutil
        ${log-lib})

整体来说,这道菜做的还是比较顺利的。


4. 编译脚本分析

编译脚本中最核心的是执行源码中的 configure 文件,这是 FFmpeg 的配置脚本。 前面的代码都是为了执行它而准备的参数:

NDK_PATH=/home/toly/SDK/AndroidSdk/ndk/26.1.10909125

指定本地 NDK 路径,根据 FFmpeg 交叉编译需要。NDK 可以通过 Android SDK 的管理工具下载:

TOOLCHAIN=$NDK_PATH/toolchains/llvm/prebuilt/linux-x86_64

TOOLCHAIN: 指定 LLVM 工具链路径,根据系统编译环境系统架构选择 linux-x86_64。我们可以进入 NDK 对应的文件夹中,看到它:


bash 复制代码
API_LEVEL=24
TARGET=aarch64-linux-android  
CC=$TOOLCHAIN/bin/${TARGET}${API_LEVEL}-clang    
CXX=$TOOLCHAIN/bin/${TARGET}${API_LEVEL}-clang++  

CCCXX: 分别为 C 和 C++ 编译器,后缀 ${API_LEVEL}-clang 是 LLVM 编译器要求的命名格式。这里对应的是这两个文件:


ini 复制代码
ARCH=arm64  # 可选:arm, arm64, x86, x86_64
CPU=armv8-a
OUTPUT_DIR=$(pwd)/android/$ARCH
  • ARCH=arm64: 编译架构,这里是 arm64,对应的目标是 aarch64-linux-android
  • CPU=armv8-a: 目标 CPU 架构,这里编译 armv8-a
  • OUTPUT_DIR: 编译产物输出目录,当前路径下的 android/arm64

然后是执行 configure 脚本:

bash 复制代码
# 执行 FFmpeg 配置
./configure \
  --target-os=android \
  --prefix=$OUTPUT_DIR \
  --arch=aarch64 \
  --cpu=$CPU \
  --cc=$CC \
  --cxx=$CXX \
  --strip=$TOOLCHAIN/bin/llvm-strip \
  --enable-cross-compile \
  --sysroot=$TOOLCHAIN/sysroot \
  --enable-shared \
  --disable-static \
  --disable-doc \
  --disable-programs \
  --disable-avdevice \
  --disable-avfilter \
  --disable-postproc \
  --disable-symver \
  --extra-cflags="-O3 -fPIC"
  • --target-os=android:目标平台为 Android
  • --prefix:安装路径(输出路径)
  • --arch=aarch64:设置目标架构
  • --cpu=armv8-a:设置目标 CPU 架构,arm64 架构常见选项
  • --cc / --cxx:使用 clang 交叉编译器
  • --strip:使用 LLVM 工具链提供的 strip 工具去除符号
  • --enable-cross-compile:开启交叉编译
  • --sysroot:NDK 的 sysroot,指定头文件与库路径
  • --enable-shared / --disable-static:只生成 .so 动态库
  • --disable-doc / --disable-programs:不构建文档与工具程序(如 ffmpeg 命令行工具)
  • --disable-avdevice --disable-avfilter --disable-postproc:裁剪不必要的功能模块,减小体积
  • --disable-symver:禁用 symbol versioning(可能为兼容 Android)
  • --extra-cflags:添加优化选项 -O3,开启 -fPIC(位置无关代码,构建动态库必须)

5. 尾声

到这里,我们就完成了 FFmpeg7.1.1 最新版本,编译为 Android 的动态链接库,完成了万里长征的第一步。后面有机会可能会研究一下 FFmpeg,希望下一篇不会是下一个三年,再编译一个 FFmpeg 9.0, 哈哈, 敬请期待 ~

更多文章和视频知识资讯,大家可以关注我的公众号、掘金和 B 站 。

相关推荐
Aric37 分钟前
conan cross build for Android with NDK toolchain
android
隐-梵4 小时前
Android studio学习之路(六)--真机的调试以及多媒体照相的使用
android·学习·android studio
stevenzqzq4 小时前
Android Studio Logcat V2 使用指南(适配 2024 年版本)
android·ide·android studio
bytebeats4 小时前
改进 Jetpack Compose 中的 ModalBottomSheet API
android
bytebeats4 小时前
使用Dagger SPI 查找非必要组件依赖项
android·gradle·dagger
bytebeats4 小时前
在Kotlin中编写依赖于时间的可测试协程代码
android·kotlin·测试
_一条咸鱼_4 小时前
AI 大模型之 Transformer 架构深入剖析
android
QING6184 小时前
Kotlin 中 reified 配合 inline 不再被类型擦除蒙蔽双眼
android·kotlin·app
Yang-Never5 小时前
OpenGL ES -> SurfaceView + EGL实现立方体纹理贴图+透视效果
android·kotlin·android studio·贴图
QING6185 小时前
Android应用启动与退出监听方案——新手入门指南
android·架构·app