一.环境与下载资源
1.1.环境:Linux虚拟机,Ubuntu 20.04.6
1.2.下载资源
-
下载Ffmpeg
- 下载最新版本的命令:git clone https://git.ffmpeg.org/ffmpeg.git ffmpeg
- 下载指定版的命令:wget https://ffmpeg.org/releases/ffmpeg-7.1.1.tar.bz2
- 查看ffmpeg相关版本的地址:https://www.ffmpeg.org/releases/
-
解压命令
- 安装:sudo apt -y install bzip2,执行解压操作:tar -jxvpf ffmpeg-7.1.1.tar.bz2
-
下载NDK
- Android DNK官网
- 命令:wget https://dl.google.com/android/repository/android-ndk-r26-linux.zip
- 解压:unzip android-ndk-r26-linux.zip
二.配置NDK环境变量
-
NDK是有多个位置可以配置环境变量的,我们选择修改~/.bashrc即可
-
执行命令:vim ~/.bashrc,添加如下信息(添加完成通过wq进行保存,需要对vim有一点点了解):
# 在文件末尾添加 ndk环境变量(/home/jack/android-ndk-r26根据pwd命令查看)
export NDKROOT=/home/jack/android-ndk-r26
export PATH=$NDKROOT:$PATH
- 执行命令:source ~/.bashrc
- 接着通过ndk-build检测环境变量是否配置成功
jack@jack-pc:~$ ndk-build
Android NDK: Could not find application project directory !
Android NDK: Please define the NDK_PROJECT_PATH variable to point to it.
/home/jack/android-ndk-r26/build/core/build-local.mk:151: *** Android NDK: Aborting . Stop.
三.修改configure文件
-
configure位于/home/jack/ffmpeg-7.1.1中,将文件复制下来,再修改,然后替换
- 由于编译出来的动态库文件名的版本号在.so之后(例如“libavcodec.so.5.100.1”),而Android平台不能识别这样的文件名,所以需要修改这种文件名。
-
修改的信息如下
- configure的文件内容比较多,通过notepad++搜索# build settings,大概是4100多行的位置
# 将ffmpeg-7.1.1目录中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)'
四.安装yasm的汇编编译器
- 执行命令:apt install yasm -y
- 如果不安装,在执行后面编写的编译脚本时可能会存在报错
nasm/yasm not found or too old. Use --disable-x86asm for a crippled build
五.编写编译脚本
-
如取名为build_android.sh,将一下内容复制进去即可,将文件放到ffmpeg-7.1.1目录中
- 注意
- 一共可以编译4个平台的,需要编译几个平台,自行设置。
- 注意
-
以下是错误的脚本,正确的脚本文件在6.3中,保留是为了记录遇到的坑。
#!/bin/bash
NDK=/home/jack/android-ndk-r26
#工具链路径,根据系统调整
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64
#目标 Android API 级别,即兼容性:编译出的 FFmpeg 库最低可运行在 Android 8.0 及以上设备
API=26
function build_android
{
echo "Compiling FFmpeg for $CPU"
./configure \
#设置安装路径
--prefix=$PREFIX \
--enable-neon \
# 禁用硬件加速
--disable-hwaccels \
# 禁用 GPL 代码(使用 LGPL)
--disable-gpl \
# 禁用后期处理
--disable-postproc \
# 生成动态库
--enable-shared \
# 启用 JNI 支持
--enable-jni \
# 禁用 MediaCodec
--enable-mediacodec \
#启用 H264 硬件解码
--enable-decoder=h264_mediacodec \
# 不生成静态库
--disable-static \
# 不构建文档
--disable-doc \
# 不构建 ffmpeg 命令行工具
--disable-ffmpeg \
# 不构建 ffplay
--disable-ffplay \
# 不构建 ffprobe
--disable-ffprobe \
# 禁用 avdevice 模块
--disable-avdevice \
# 禁用符号版本控制
--disable-symver \
# 交叉编译工具前缀
--cross-prefix=$CROSS_PREFIX \
#要编译的目标系统是Android
--target-os=android \
# 目标架构(如 arm64)
--arch=$ARCH \
# 目标 CPU 型号(如 armv8-a)
--cpu=$CPU \
#配置c编译器
--cc=$CC \
--cxx=$CXX \
#允许是一个交叉编译
--enable-cross-compile \
# 系统根目录
--sysroot=$SYSROOT \
# 额外 C 编译选项
--extra-cflags="-Os -fpic $OPTIMIZE_CFLAGS" \
# 额外链接选项
--extra-ldflags="$ADDI_LDFLAGS" \
$ADDITIONAL_CONFIGURE_FLAG
make clean
make
make install
echo "The Compilation of FFmpeg for $CPU is completed"
}
#armv8-a
# 架构类型
ARCH=arm64
# CPU 指令集
CPU=armv8-a
# C 编译器路径
CC=$TOOLCHAIN/bin/aarch64-linux-android$API-clang
# C++ 编译器路径
CXX=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++
# 系统库路径
SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
# 工具前缀
CROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android-
# 安装路径(当前目录下的 android/armv8-a)
PREFIX=$(pwd)/android/$CPU
# 优化编译选项
OPTIMIZE_CFLAGS="-march=$CPU"
build_android
#armv7-a
ARCH=arm
CPU=armv7-a
CC=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang
CXX=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang++
SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/arm-linux-androideabi-
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=vfp -marm -march=$CPU "
build_android
#x86
ARCH=x86
CPU=x86
CC=$TOOLCHAIN/bin/i686-linux-android$API-clang
CXX=$TOOLCHAIN/bin/i686-linux-android$API-clang++
SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/i686-linux-android-
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32"
build_android
#x86_64
ARCH=x86_64
CPU=x86-64
CC=$TOOLCHAIN/bin/x86_64-linux-android$API-clang
CXX=$TOOLCHAIN/bin/x86_64-linux-android$API-clang++
SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/x86_64-linux-android-
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-march=$CPU -msse4.2 -mpopcnt -m64 -mtune=intel"
build_android
- 设置编译脚本的权限
- 命令:chmod 777 build_android.sh
六.测试交叉编译效果
- 执行命令:./build_android.sh
6.1.出现报错
jack@jack-pc:~/ffmpeg-7.1.1$ ./build_android.sh
bash: ./build_android.sh: /bin/bash^M: bad interpreter: No such file or directory
-
处理方案,依次执行;
- sudo apt install dos2unix
- dos2unix build_bash.sh
-
效果如下:
6.2.脚本文件执行完毕,出现报错信息,同时没有看到生成的android目录
mkdir: cannot create directory ‘/usr/local/share/man/man1’: Permission denied
make: *** [doc/Makefile:129: install-man] Error 1
- 注意:要加上sudo,即需要执行命令:sudo ./build_android.sh
6.3.使用最新的脚本文件,加上sudo进行编译
#!/bin/bash
NDK=/home/jack/android-ndk-r26
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64
API=26
function build_android
{
echo "Compiling FFmpeg for $CPU"
./configure \
--prefix=$PREFIX \
--enable-shared \
--disable-static \
--disable-doc \
--disable-programs \
--disable-avdevice \
--disable-avfilter \
--disable-postproc \
--disable-symver \
--disable-static \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-hwaccels \
--disable-gpl \
--target-os=android \
--arch=$ARCH \
--cpu=$CPU \
--cc=$CC \
--cxx=$CXX \
--enable-cross-compile \
--sysroot=$TOOLCHAIN/sysroot \
--cross-prefix=$CROSS_PREFIX \
--extra-cflags="-Os -fpic $OPTIMIZE_CFLAGS" \
$ADDITIONAL
make clean
make -j12
make install
echo "The Compilation of FFmpeg for $CPU is completed"
}
echo "Begining Compiling FFmpeg for $CPU with ========= neon ========"
#armv8-a
# 架构类型
ARCH=arm64
# CPU 指令集
CPU=armv8-a
# C 编译器路径
CC=$TOOLCHAIN/bin/aarch64-linux-android${API}-clang
# C++ 编译器路径
CXX=$TOOLCHAIN/bin/aarch64-linux-android${API}-clang++
# 安装路径(当前目录下的 android/armv8-a)
PREFIX=$(pwd)/android/$CPU-neon-hard
# 工具前缀。根据实践以及deepseek查询(待实践中验证其正确性):设置 cross-prefix(注意现在使用 llvm 工具链),llvm- 前缀会自动处理 ar、strip 等工具,故后面省略 --strip=$TOOLCHAIN/bin/llvm-strip \
CROSS_PREFIX=$TOOLCHAIN/bin/llvm-
# 优化编译选项
OPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=neon -marm -march=$CPU "
ADDITIONAL="--enable-asm \
--enable-neon \
--enable-jni \
--enable-mediacodec \
--enable-decoder=h264_mediacodec \
--enable-hwaccel=h264_mediacodec"
build_android
echo "Begining Compiling FFmpeg for $CPU without ========= neon ========"
#armv8-a
# 架构类型
ARCH=arm64
# CPU 指令集
CPU=armv8-a
# C 编译器路径
CC=$TOOLCHAIN/bin/aarch64-linux-android${API}-clang
# C++ 编译器路径
CXX=$TOOLCHAIN/bin/aarch64-linux-android${API}-clang++
# 安装路径(当前目录下的 android/armv8-a)
PREFIX=$(pwd)/android/$CPU
# 工具前缀。根据实践以及deepseek查询(待实践中验证其正确性):设置 cross-prefix(注意现在使用 llvm 工具链),llvm- 前缀会自动处理 ar、strip 等工具,故后面省略 --strip=$TOOLCHAIN/bin/llvm-strip \
CROSS_PREFIX=$TOOLCHAIN/bin/llvm-
# 优化编译选项
OPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=vfp -marm -march=$CPU "
ADDITIONAL=""
build_android
echo "==================================================================="
#armv7-a
ARCH=arm
CPU=armv7-a
CC=$TOOLCHAIN/bin/armv7a-linux-androideabi${API}-clang
CXX=$TOOLCHAIN/bin/armv7a-linux-androideabi${API}-clang++
CROSS_PREFIX=$TOOLCHAIN/bin/llvm-
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=vfp -marm -march=$CPU "
ADDITIONAL=""
build_android
echo "==================================================================="
#x86
ARCH=x86
CPU=x86
CC=$TOOLCHAIN/bin/i686-linux-android${API}-clang
CXX=$TOOLCHAIN/bin/i686-linux-android${API}-clang++
CROSS_PREFIX=$TOOLCHAIN/bin/llvm-
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32"
ADDITIONAL=""
build_android
echo "==================================================================="
#x86_64
ARCH=x86_64
CPU=x86-64
CC=$TOOLCHAIN/bin/x86_64-linux-android${API}-clang
CXX=$TOOLCHAIN/bin/x86_64-linux-android${API}-clang++
CROSS_PREFIX=$TOOLCHAIN/bin/llvm-
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-march=$CPU -msse4.2 -mpopcnt -m64 -mtune=intel"
ADDITIONAL=""
build_android
6.4.查看编译结果
- 脚本文件是写了要生成5个的,但是最后两个跟x86相关的并未生成。查到的报错信息如下:
/home/jack/android-ndk-r26/toolchains/llvm/prebuilt/linux-x86_64/bin/i686-linux-android26-clang is unable to create an executable file
/home/jack/android-ndk-r26/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android26-clang is unable to create an executable file
- 在NDK对应的文件夹中能找到提到的两个文件,但是为什么没有生成跟x86相关的具体原因不清楚,有知道的同学欢迎指出。
七.遇到的2个问题
7.1.问题1:不产生指定的android文件
- 原因:没有正确地去添加注释,将build_android函数中的注释去掉
7.2.CROSS_PREFIX配置错误
- 更改了ndk的版本,对应的CROSS_PREFIX需要做更改,借助了deepseek对CROSS_PREFIX进行赋值,不过具体需要实践才能验证其正确性。
八.总结
- Ffmpeg交叉编译,实践起来遇到的问题还是比较多的,其中脚本的编写还是存在一定的难度,版本需求等不同编写的内容差异可能比较大。
评论区