在 Linux 环境下交叉编译 Android 的 FFmpeg 库的完整指南:
环境准备
1. 安装 Android NDK
# 方法一:使用 Android Studio SDK Manager
# Tools -> SDK Manager -> SDK Tools -> NDK (Side by side)
# 方法二:命令行安装
sdkmanager "ndk;25.1.8937393"
# 方法三:直接下载
wget https://dl.google.com/android/repository/android-ndk-r25c-linux.zip
unzip android-ndk-r25c-linux.zip
export ANDROID_NDK_HOME=/path/to/android-ndk-r25c
2. 安装必要工具
# Ubuntu/Debian
sudo apt update
sudo apt install -y \
build-essential \
autoconf \
automake \
libtool \
pkg-config \
yasm \
nasm \
git \
wget \
make
# 创建工作目录
mkdir -p ~/android_ffmpeg/{sources,build,output}
cd ~/android_ffmpeg
编译依赖库
1. 编译 LAME 库
# 下载 LAME
cd ~/android_ffmpeg/sources
wget http://downloads.sourceforge.net/project/lame/lame/3.100/lame-3.100.tar.gz
tar -xzf lame-3.100.tar.gz
cd lame-3.100
# 创建构建脚本
cat > build_android.sh << 'EOF'
#!/bin/bash
NDK_ROOT=$ANDROID_NDK_HOME
TOOLCHAIN=$NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64
PLATFORM=$TOOLCHAIN/sysroot
function build_lame() {
API=$1
ARCH=$2
CPU=$3
PREFIX=$4
./configure \
--prefix=$PREFIX \
--host=$CPU-linux-android$API \
--disable-shared \
--enable-static \
--disable-frontend \
CC=$TOOLCHAIN/bin/$CPU-linux-android$API-clang \
CXX=$TOOLCHAIN/bin/$CPU-linux-android$API-clang++ \
AR=$TOOLCHAIN/bin/llvm-ar \
AS=$TOOLCHAIN/bin/$CPU-linux-android$API-as \
LD=$TOOLCHAIN/bin/$CPU-linux-android$API-ld \
RANLIB=$TOOLCHAIN/bin/llvm-ranlib \
STRIP=$TOOLCHAIN/bin/$CPU-linux-android$API-strip \
CFLAGS="-fPIC" \
LDFLAGS="-fPIC"
make clean
make -j$(nproc)
make install
}
# 构建不同架构
build_lame 21 armv7a armv7a-linux-androideabi ~/android_ffmpeg/build/lame/armv7a
build_lame 21 aarch64 aarch64-linux-android ~/android_ffmpeg/build/lame/aarch64
build_lame 21 x86 i686-linux-android ~/android_ffmpeg/build/lame/x86
build_lame 21 x86_64 x86_64-linux-android ~/android_ffmpeg/build/lame/x86_64
EOF
chmod +x build_android.sh
./build_android.sh
2. 编译其他依赖库(可选)
# Ogg 库
cd ~/android_ffmpeg/sources
wget https://ftp.osuosl.org/pub/xiph/releases/ogg/libogg-1.3.5.tar.gz
tar -xzf libogg-1.3.5.tar.gz
cd libogg-1.3.5
# Vorbis 库
cd ~/android_ffmpeg/sources
wget https://ftp.osuosl.org/pub/xiph/releases/vorbis/libvorbis-1.3.7.tar.gz
tar -xzf libvorbis-1.3.7.tar.gz
cd libvorbis-1.3.7
编译 FFmpeg
1. 下载 FFmpeg 源码
cd ~/android_ffmpeg/sources
git clone https://git.ffmpeg.org/ffmpeg.git
cd ffmpeg
2. 创建交叉编译脚本
cat > build_android_ffmpeg.sh << 'EOF'
#!/bin/bash
NDK_ROOT=$ANDROID_NDK_HOME
TOOLCHAIN=$NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64
PLATFORM=$TOOLCHAIN/sysroot
COMMON_CONFIGURE_FLAGS="
--enable-cross-compile \
--target-os=android \
--disable-shared \
--enable-static \
--disable-programs \
--disable-doc \
--disable-htmlpages \
--disable-manpages \
--disable-podpages \
--disable-txtpages \
--disable-network \
--disable-everything \
--enable-encoder=libmp3lame \
--enable-decoder=mp3*,pcm* \
--enable-muxer=mp3,wav \
--enable-demuxer=mp3,wav \
--enable-parser=mpegaudio \
--enable-filter=aresample \
--enable-protocol=file \
--enable-swresample \
--enable-avutil \
--enable-avcodec \
--enable-avformat \
--enable-small \
--enable-neon \
--enable-thumb \
--pkg-config-flags=--static \
--extra-cflags="-fPIC" \
--extra-ldflags="-fPIC" \
--extra-libs="-lm -lz"
"
function build_ffmpeg() {
API=$1
ARCH=$2
CPU=$3
PREFIX=$4
ADDI_CFLAGS=$5
# 创建临时构建目录
rm -rf build_$ARCH
mkdir -p build_$ARCH
cd build_$ARCH
# 配置
../configure \
--prefix=$PREFIX \
--arch=$ARCH \
--cpu=$CPU \
--cc=$TOOLCHAIN/bin/$CPU-linux-android$API-clang \
--cxx=$TOOLCHAIN/bin/$CPU-linux-android$API-clang++ \
--cross-prefix=$TOOLCHAIN/bin/$CPU-linux-android$API- \
--nm=$TOOLCHAIN/bin/llvm-nm \
--strip=$TOOLCHAIN/bin/$CPU-linux-android$API-strip \
--extra-cflags="-Os -fpic $ADDI_CFLAGS" \
--extra-ldflags="-L$PREFIX/lib" \
--enable-libmp3lame \
--extra-cflags="-I$PREFIX/include" \
$COMMON_CONFIGURE_FLAGS
# 编译
make clean
make -j$(nproc)
make install
cd ..
}
# 构建不同架构
build_ffmpeg 21 armv7a armv7a-linux-androideabi ~/android_ffmpeg/build/lame/armv7a "-march=armv7-a -mfloat-abi=softfp -mfpu=neon"
build_ffmpeg 21 aarch64 aarch64-linux-android ~/android_ffmpeg/build/lame/aarch64 "-march=armv8-a"
build_ffmpeg 21 x86 i686-linux-android ~/android_ffmpeg/build/lame/x86 "-march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32"
build_ffmpeg 21 x86_64 x86_64-linux-android ~/android_ffmpeg/build/lame/x86_64 "-march=x86-64 -msse4.2 -mpopcnt -m64 -mtune=intel"
EOF
chmod +x build_android_ffmpeg.sh
3. 简化版本的编译脚本
cat > build_simple.sh << 'EOF'
#!/bin/bash
NDK_ROOT=$ANDROID_NDK_HOME
TOOLCHAIN=$NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64
# 构建函数
build_arch() {
local API=$1
local ARCH=$2
local CPU=$3
local HOST=$4
local EXTRA_CFLAGS=$5
local OUTPUT_DIR=~/android_ffmpeg/output/$ARCH
echo "Building for $ARCH..."
# 清理
rm -rf build_$ARCH
mkdir -p build_$ARCH
cd ffmpeg
# 配置
./configure \
--prefix=$OUTPUT_DIR \
--enable-cross-compile \
--target-os=android \
--arch=$ARCH \
--cpu=$CPU \
--cc=$TOOLCHAIN/bin/$HOST$API-clang \
--cxx=$TOOLCHAIN/bin/$HOST$API-clang++ \
--cross-prefix=$TOOLCHAIN/bin/$HOST$API- \
--nm=$TOOLCHAIN/bin/llvm-nm \
--ar=$TOOLCHAIN/bin/llvm-ar \
--as=$TOOLCHAIN/bin/$HOST$API-as \
--strip=$TOOLCHAIN/bin/$HOST$API-strip \
--extra-cflags="-fPIC -DANDROID -D__ANDROID_API__=$API $EXTRA_CFLAGS" \
--extra-ldflags="-fPIC" \
--enable-shared \
--disable-static \
--disable-programs \
--disable-doc \
--disable-htmlpages \
--disable-manpages \
--disable-podpages \
--disable-txtpages \
--disable-network \
--enable-libmp3lame \
--extra-cflags="-I~/android_ffmpeg/build/lame/$ARCH/include" \
--extra-ldflags="-L~/android_ffmpeg/build/lame/$ARCH/lib" \
--enable-encoder=libmp3lame,pcm_s16le \
--enable-decoder=mp3,pcm_s16le \
--enable-muxer=mp3,wav \
--enable-demuxer=mp3,wav \
--enable-parser=mpegaudio \
--enable-filter=aresample \
--enable-protocol=file \
--enable-swresample \
--enable-avutil \
--enable-avcodec \
--enable-avformat \
--enable-small
# 编译和安装
make clean
make -j$(nproc)
make install
cd ..
}
# 构建所有架构
mkdir -p ~/android_ffmpeg/output
build_arch 21 arm armv7a-linux-androideabi armv7a-linux-androideabi "-march=armv7-a -mfloat-abi=softfp -mfpu=neon"
build_arch 21 aarch64 aarch64-linux-android aarch64-linux-android "-march=armv8-a"
build_arch 21 x86 i686-linux-android i686-linux-android "-march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32"
build_arch 21 x86_64 x86_64-linux-android x86_64-linux-android "-march=x86-64 -msse4.2 -mpopcnt -m64 -mtune=intel"
EOF
chmod +x build_simple.sh
创建统一的构建脚本
cat > build_android_all.sh << 'EOF'
#!/bin/bash
# 设置环境变量
export ANDROID_NDK_HOME=${ANDROID_NDK_HOME:-/opt/android-ndk-r25c}
NDK_ROOT=$ANDROID_NDK_HOME
TOOLCHAIN=$NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64
# 创建目录
WORK_DIR=~/android_ffmpeg
mkdir -p $WORK_DIR/{sources,build,output}
cd $WORK_DIR/sources
# 下载源码(如果需要)
if [ ! -d "ffmpeg" ]; then
git clone https://git.ffmpeg.org/ffmpeg.git
fi
if [ ! -d "lame-3.100" ]; then
wget -c http://downloads.sourceforge.net/project/lame/lame/3.100/lame-3.100.tar.gz
tar -xzf lame-3.100.tar.gz
fi
# 架构配置
declare -A ARCH_CONFIGS=(
["armv7a"]="arm armv7a-linux-androideabi -march=armv7-a -mfloat-abi=softfp -mfpu=neon"
["aarch64"]="aarch64 aarch64-linux-android -march=armv8-a"
["x86"]="x86 i686-linux-android -march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32"
["x86_64"]="x86_64 x86_64-linux-android -march=x86-64 -msse4.2 -mpopcnt -m64 -mtune=intel"
)
# 构建 LAME
build_lame() {
local API=$1
local ARCH=$2
local CPU=$3
local PREFIX=$WORK_DIR/build/lame/$ARCH
echo "Building LAME for $ARCH..."
cd $WORK_DIR/sources/lame-3.100
make clean
./configure \
--prefix=$PREFIX \
--host=$CPU-linux-android$API \
--disable-shared \
--enable-static \
--disable-frontend \
CC=$TOOLCHAIN/bin/$CPU-linux-android$API-clang \
CXX=$TOOLCHAIN/bin/$CPU-linux-android$API-clang++ \
AR=$TOOLCHAIN/bin/llvm-ar \
AS=$TOOLCHAIN/bin/$CPU-linux-android$API-as \
LD=$TOOLCHAIN/bin/$CPU-linux-android$API-ld \
RANLIB=$TOOLCHAIN/bin/llvm-ranlib \
STRIP=$TOOLCHAIN/bin/$CPU-linux-android$API-strip \
CFLAGS="-fPIC" \
LDFLAGS="-fPIC"
make -j$(nproc)
make install
}
# 构建 FFmpeg
build_ffmpeg() {
local API=$1
local ARCH=$2
local CPU=$3
local HOST=$4
local EXTRA_CFLAGS=$5
local OUTPUT_DIR=$WORK_DIR/output/$ARCH
echo "Building FFmpeg for $ARCH..."
cd $WORK_DIR/sources/ffmpeg
# 清理
make clean
# 配置
./configure \
--prefix=$OUTPUT_DIR \
--enable-cross-compile \
--target-os=android \
--arch=$ARCH \
--cpu=$CPU \
--cc=$TOOLCHAIN/bin/$HOST$API-clang \
--cxx=$TOOLCHAIN/bin/$HOST$API-clang++ \
--cross-prefix=$TOOLCHAIN/bin/$HOST$API- \
--nm=$TOOLCHAIN/bin/llvm-nm \
--ar=$TOOLCHAIN/bin/llvm-ar \
--as=$TOOLCHAIN/bin/$HOST$API-as \
--strip=$TOOLCHAIN/bin/$HOST$API-strip \
--extra-cflags="-fPIC -DANDROID -D__ANDROID_API__=$API $EXTRA_CFLAGS" \
--extra-ldflags="-fPIC -L$WORK_DIR/build/lame/$ARCH/lib" \
--extra-cxxflags="-fPIC" \
--enable-shared \
--disable-static \
--disable-programs \
--disable-doc \
--disable-htmlpages \
--disable-manpages \
--disable-podpages \
--disable-txtpages \
--disable-network \
--enable-libmp3lame \
--extra-cflags="-I$WORK_DIR/build/lame/$ARCH/include" \
--enable-encoder=libmp3lame,pcm_s16le \
--enable-decoder=mp3,pcm_s16le \
--enable-muxer=mp3,wav \
--enable-demuxer=mp3,wav \
--enable-parser=mpegaudio \
--enable-filter=aresample \
--enable-protocol=file \
--enable-swresample \
--enable-avutil \
--enable-avcodec \
--enable-avformat \
--enable-small \
--enable-jni \
--enable-mediacodec
# 编译和安装
make -j$(nproc)
make install
}
# 主构建过程
API_LEVEL=21
# 为每个架构构建 LAME 和 FFmpeg
for ARCH in "${!ARCH_CONFIGS[@]}"; do
CONFIG=(${ARCH_CONFIGS[$ARCH]})
ARCH_NAME=${CONFIG[0]}
CPU=${CONFIG[1]}
CFLAGS=${CONFIG[2]}
HOST=$CPU
echo "=== Building for $ARCH ==="
# 构建 LAME
build_lame $API_LEVEL $ARCH_NAME $CPU
# 构建 FFmpeg
build_ffmpeg $API_LEVEL $ARCH_NAME $CPU $HOST "$CFLAGS"
done
echo "=== Build completed ==="
echo "Output files are in: $WORK_DIR/output/"
EOF
chmod +x build_android_all.sh
创建 CMakeLists.txt 用于 Android 项目
# CMakeLists.txt for Android FFmpeg
cmake_minimum_required(VERSION 3.18.1)
project("ffmpeg_android")
# 设置架构
set(FFMPEG_ARCH ${ANDROID_ABI})
# FFmpeg 路径
set(FFMPEG_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/ffmpeg/${FFMPEG_ARCH})
# 包含目录
include_directories(
${FFMPEG_ROOT}/include
)
# 库目录
link_directories(
${FFMPEG_ROOT}/lib
)
# 添加库
add_library(
ffmpeg_android
SHARED
ffmpeg_jni.cpp
)
# 链接 FFmpeg 库
target_link_libraries(
ffmpeg_android
avformat
avcodec
avutil
swresample
swscale
postproc
avfilter
mp3lame
log
android
)
创建 JNI 接口示例
// ffmpeg_jni.cpp
#include <jni.h>
#include <android/log.h>
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>
#include <libswresample/swresample.h>
}
#define LOG_TAG "FFmpegAndroid"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
extern "C"
JNIEXPORT jstring JNICALL
Java_com_yourpackage_FFmpegHelper_getFFmpegVersion(JNIEnv *env, jobject thiz) {
const char* version = av_version_info();
LOGI("FFmpeg Version: %s", version);
return env->NewStringUTF(version);
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_yourpackage_FFmpegHelper_initFFmpeg(JNIEnv *env, jobject thiz) {
avformat_network_init();
LOGI("FFmpeg initialized");
return JNI_TRUE;
}
验证构建结果
# 检查生成的文件
ls -la ~/android_ffmpeg/output/*/lib/
ls -la ~/android_ffmpeg/output/*/include/
# 检查库的架构
file ~/android_ffmpeg/output/armv7a/lib/*.so
打包脚本
cat > package_ffmpeg.sh << 'EOF'
#!/bin/bash
WORK_DIR=~/android_ffmpeg
OUTPUT_DIR=$WORK_DIR/output
PACKAGE_DIR=$WORK_DIR/package
# 创建包目录
rm -rf $PACKAGE_DIR
mkdir -p $PACKAGE_DIR/include
mkdir -p $PACKAGE_DIR/libs/{armeabi-v7a,arm64-v8a,x86,x86_64}
# 复制头文件(从任意架构复制,因为头文件是通用的)
cp -r $OUTPUT_DIR/armv7a/include/* $PACKAGE_DIR/include/
# 复制库文件
cp $OUTPUT_DIR/armv7a/lib/*.so $PACKAGE_DIR/libs/armeabi-v7a/
cp $OUTPUT_DIR/aarch64/lib/*.so $PACKAGE_DIR/libs/arm64-v8a/
cp $OUTPUT_DIR/x86/lib/*.so $PACKAGE_DIR/libs/x86/
cp $OUTPUT_DIR/x86_64/lib/*.so $PACKAGE_DIR/libs/x86_64/
# 创建 zip 包
cd $PACKAGE_DIR
zip -r ffmpeg_android.zip include libs
echo "Package created: $PACKAGE_DIR/ffmpeg_android.zip"
EOF
chmod +x package_ffmpeg.sh
./package_ffmpeg.sh
使用说明
1. 设置环境变量
export ANDROID_NDK_HOME=/path/to/your/ndk
export PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH
2. 执行构建
cd ~/android_ffmpeg
./build_android_all.sh
3. 在 Android 项目中使用
将生成的库文件复制到 Android 项目的 src/main/jniLibs/
目录下对应的架构文件夹中。
完成这些步骤后,你就有了可以在 Android 项目中使用的 FFmpeg 库,支持 MP3 LAME 编解码器。