编译前的准备
Android NDK r21e(21.2.6472646)需要准备Linux版本和Windows版本
编译过程及脚本
主要流程:先编译好准备的第三方库,生成相应的动态库文件,最后在编译FFmpeg时关联起来。在实际应用中可能还需要编译不同的ABI才能在不同的设备上使用,本文FFmpeg以编译arm64-v8a为例。
存储目录结构
Shell
home
├── ffmpeg_build
│ └── out
│ └── arm64-v8a
└── ffmpeg_sources
├── ffmpeg-4.3.1
├── ndk
├── x264
└── other_libs # 存储第三方库编译的动态库文件
└── x264
编译第三方库
x264
Shell
#!/bin/bash
set -e
NDK=# 实际ndk路径
X264_SRC=# 实际X264源码路径
INSTALL_BASE=# 实际存储第三方库编译的动态库文件路径
API=21
ABIS=("armeabi-v7a" "arm64-v8a" "x86" "x86_64")
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64
for ABI in "${ABIS[@]}"; do
echo "============================="
echo " 正在构建 ABI: $ABI"
echo "============================="
case $ABI in
armeabi-v7a)
TARGET=armv7a-linux-androideabi
ARCH=arm
CROSS_PREFIX=$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/arm-linux-androideabi-
CC=$TOOLCHAIN/bin/armv7a-linux-androideabi${API}-clang
;;
arm64-v8a)
TARGET=aarch64-linux-android
ARCH=arm64
CROSS_PREFIX=$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-
CC=$TOOLCHAIN/bin/aarch64-linux-android${API}-clang
;;
x86)
TARGET=i686-linux-android
ARCH=x86
CROSS_PREFIX=$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/i686-linux-android-
CC=$TOOLCHAIN/bin/i686-linux-android${API}-clang
;;
x86_64)
TARGET=x86_64-linux-android
ARCH=x86_64
CROSS_PREFIX=$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android-
CC=$TOOLCHAIN/bin/x86_64-linux-android${API}-clang
;;
*)
echo " Unsupported ABI: $ABI"
exit 1
;;
esac
BUILD_DIR=$X264_SRC/build/$ABI
INSTALL_DIR=$INSTALL_BASE/$ABI/x264
mkdir -p "$BUILD_DIR" "$INSTALL_DIR"
rm -rf "$BUILD_DIR"/*
cd "$BUILD_DIR"
echo " 配置 x264 for $ABI"
# 设置 sysroot 为 llvm 自带的 sysroot,兼容新 NDK
SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
# 设置环境变量,指定交叉编译器和 sysroot
export CC=$CC
export CFLAGS="--sysroot=$SYSROOT"
export LDFLAGS="--sysroot=$SYSROOT"
$X264_SRC/configure \
--prefix="$INSTALL_DIR" \
--host=$TARGET \
--enable-shared \
--disable-cli \
--enable-pic \
--disable-asm \
--sysroot="$SYSROOT"
echo " 编译 x264 动态库"
make -j$(nproc)
make install
echo " 静态库完成: $INSTALL_DIR/lib/libx264.a"
echo
done
echo " 所有 ABI 构建完成,输出在: $INSTALL_BASE/<abi>/x264"
随后切换到FFmpeg目录下,新建以下脚本
Shell
#!/bin/bash
set -e
NDK=/home/puffy/sang/ffmpeg_sources/ndk/21.2.6472646/android-ndk-r21e
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64
API=21
ARCH=arm64-v8a
CPU=armv8-a
PLATFORM=aarch64-linux-android
PREFIX=/home/puffy/sang/ffmpeg_build/out/$ARCH
X264_PATH=/home/puffy/sang/ffmpeg_sources/other_libs/$ARCH/x264
export CC=$TOOLCHAIN/bin/${PLATFORM}${API}-clang
export CXX=$TOOLCHAIN/bin/${PLATFORM}${API}-clang++
export AR=$TOOLCHAIN/bin/aarch64-linux-android-ar
export LD=$TOOLCHAIN/bin/aarch64-linux-android-ld
export NM=$TOOLCHAIN/bin/aarch64-linux-android-nm
export STRIP=$TOOLCHAIN/bin/aarch64-linux-android-strip
export PKG_CONFIG_PATH=$X264_PATH/lib/pkgconfig
./configure \
--prefix=$PREFIX \
--target-os=android \
--arch=aarch64 \
--cpu=$CPU \
--enable-cross-compile \
--cross-prefix=$TOOLCHAIN/bin/aarch64-linux-android- \
--cc=$CC \
--cxx=$CXX \
--sysroot=$TOOLCHAIN/sysroot \
--enable-gpl \
--enable-libx264 \
--enable-shared \
--disable-static \
--disable-doc \
--disable-programs \
--disable-symver \
--extra-cflags="-I$X264_PATH/include -march=$CPU" \
--extra-ldflags="-L$X264_PATH/lib"
make -j$(nproc)
make install
# 拷贝 libx264.so
X264_SO=$X264_PATH/lib/libx264.so
DEST_SO_DIR=$PREFIX/lib
if [ -f "$X264_SO" ]; then
echo " 拷贝 libx264.so 到 FFmpeg 输出目录:$DEST_SO_DIR"
cp -v "$X264_SO" "$DEST_SO_DIR/"
else
echo " 未找到 libx264.so,请确认 x264 已正确编译:$X264_SO"
exit 1
fi
# 拷贝 include 头文件
X264_INCLUDE_DIR=$X264_PATH/include
DEST_INCLUDE_DIR=$PREFIX/include/x264
if [ -d "$X264_INCLUDE_DIR" ]; then
echo " 拷贝 x264 include 头文件到:$DEST_INCLUDE_DIR"
mkdir -p "$DEST_INCLUDE_DIR"
cp -v "$X264_INCLUDE_DIR"/*.h "$DEST_INCLUDE_DIR/"
else
echo " 未找到 x264 include 目录,请确认路径:$X264_INCLUDE_DIR"
exit 1
fi
echo " 编译完成,所有文件已就绪"
如果需要编译其他ABI或别的第三方库可参看github
编译成功后可在输出文件得到以下内容

在新建Native C++ 项目后,将ndk配置为和之前在Linux编译的ndk版本一致,新建jniLibs/arm64-v8a,lib文件下的so文件拷贝到此处

include下的文件拷贝到cpp/ffmpeg/include下

随后在CMakeList引入FFmpeg
txt
# 支持gnu++11
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0 -g")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -g")
set(CMAKE_BUILD_TYPE Debug)
# 1. 定义so库和头文件所在目录,方面后面使用
set(ffmpeg_lib_dir ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})
set(ffmpeg_head_dir ${CMAKE_SOURCE_DIR}/ffmpeg)
# 2. 添加头文件目录
include_directories(${ffmpeg_head_dir}/include)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-rpath=$ORIGIN") #注意:告诉 CMake 不要使用 .so 的 SONAME
# 3. 添加ffmpeg相关的so库
add_library(avutil
SHARED
IMPORTED)
set_target_properties(avutil
PROPERTIES IMPORTED_LOCATION
${ffmpeg_lib_dir}/libavutil.so)
add_library(swresample
SHARED
IMPORTED)
set_target_properties(swresample
PROPERTIES IMPORTED_LOCATION
${ffmpeg_lib_dir}/libswresample.so)
add_library(avcodec
SHARED
IMPORTED)
set_target_properties(avcodec
PROPERTIES IMPORTED_LOCATION
${ffmpeg_lib_dir}/libavcodec.so)
add_library(avfilter
SHARED
IMPORTED)
set_target_properties(avfilter
PROPERTIES IMPORTED_LOCATION
${ffmpeg_lib_dir}/libavfilter.so)
add_library(swscale
SHARED
IMPORTED)
set_target_properties(swscale
PROPERTIES IMPORTED_LOCATION
${ffmpeg_lib_dir}/libswscale.so)
add_library(avformat
SHARED
IMPORTED)
set_target_properties(avformat
PROPERTIES IMPORTED_LOCATION
${ffmpeg_lib_dir}/libavformat.so)
add_library(avdevice
SHARED
IMPORTED)
set_target_properties(avdevice
PROPERTIES IMPORTED_LOCATION
${ffmpeg_lib_dir}/libavdevice.so)
add_library(postproc
SHARED
IMPORTED)
set_target_properties(postproc
PROPERTIES
IMPORTED_LOCATION
${ffmpeg_lib_dir}/libpostproc.so
)
add_library(x264 SHARED IMPORTED)
set_target_properties(x264
PROPERTIES
IMPORTED_LOCATION ${ffmpeg_lib_dir}/libx264.so
IMPORTED_NO_SONAME TRUE
#注意
#未设置 IMPORTED_NO_SONAME
#如果第三方库是外部提供的 .so 文件(例如手动编译的 libx264.so),而你又不希望 CMake 写入 .so 的完整路径(而是仅写成 libx264.so),你应该显式关闭 SONAME:
)
# 查找代码中使用到的系统库
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log)
# 配置目标so库编译信息
add_library( # Sets the name of the library.
native-lib
SHARED
)
target_link_libraries(
native-lib
-landroid
# 打开opensl es支持
OpenSLES
-lEGL
-lGLESv2
postproc
avutil
swresample
avcodec
avfilter
swscale
avformat
avdevice
x264
${log-lib}
)
后续
如果因为配置原因无法安装虚拟机,也可以在Windows环境下配置msys2 进行以上步骤