一、准备工作:下载所需资源
| 资源 | 版本/说明 | 下载地址 |
|---|---|---|
| FFmpeg 源码 | 7.1.5(与 Qt 6.11 内置版本一致) | https://ffmpeg.org/releases/ffmpeg-7.1.5.tar.gz |
| Android NDK | Windows 版r26b (26.1.10909125) 或 r26d (26.3.11579264) | https://developer.android.com/ndk/downloads |
| MSYS2 | 提供 Windows 下的类 Unix 编译环境 | https://www.msys2.org/ |
⚠️关键点:NDK 必须下载Windows 版(
android-ndk-r26d-windows.zip),不能使用 Linux 版。
这只下载了FFmpeg 7.1.5源码和MSYS2,Android NDK使用QT自带的,目录位于/e/Android/android-sdk/ndk/27.2.12479018
二、配置 MSYS2 编译环境
安装 MSYS2 后,打开MSYS2 MINGW64终端(不是普通 MSYS2 终端)。
安装编译依赖:
pacman-S--noconfirmmakeyasm diffutils设置环境变量(根据实际路径修改):
exportPATH=/e/Qt/Tools/mingw1310_64/bin:$PATHexportANDROID_NDK_ROOT=/e/Android/android-sdk/ndk/27.2.12479018
三、在 Windows 下编译 FFmpeg for Android
解压 FFmpeg 源码到不含中文和空格的路径,例如
/e/ffmpeg/ffmpeg-7.1.5/ffmpeg-7.1.5。在源码目录下创建
build_android.sh:#!/bin/bash# 设置目标架构(这里以 arm64-v8a 为例)ARCH=aarch64CPU=armv8-aTOOLCHAIN_ARCH=aarch64-linux-android# NDK 工具链路径TOOLCHAIN=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/windows-x86_64# 最低支持的 Android API 级别,建议与你的 Qt 项目一致API=28# 进入源码目录cd/e/ffmpeg/ffmpeg-7.1.5/ffmpeg-7.1.5# 配置 FFmpeg./configure\--prefix=./install-android/$ARCH\--target-os=android\--arch=$ARCH\--cpu=$CPU\--enable-cross-compile\--cross-prefix=$TOOLCHAIN/bin/llvm-\--cc=$TOOLCHAIN/bin/${TOOLCHAIN_ARCH}${API}-clang\--cxx=$TOOLCHAIN/bin/${TOOLCHAIN_ARCH}${API}-clang++\--sysroot=$TOOLCHAIN/sysroot\--enable-shared\--disable-static\--disable-doc\--disable-programs\--enable-network# 开始编译,-j 后面的数字建议设为 CPU 核心数make-j8makeinstall其他编译方式
3.1 build_x86.sh
#!/bin/bash# =========================================# FFmpeg for Android - x86# =========================================set-eexportANDROID_NDK_ROOT=/e/Android/android-sdk/ndk/27.2.12479018API=28ABI_NAME="x86"ARCH="x86"CPU="i686"TOOLCHAIN_ARCH="i686-linux-android"case"$(uname-s)"inMINGW*|MSYS*|CYGWIN*)HOST_TAG=windows-x86_64;;Linux*)HOST_TAG=linux-x86_64;;*)echo"不支持的主机平台";exit1;;esacTOOLCHAIN=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/$HOST_TAGSYSROOT=$TOOLCHAIN/sysrootSOURCE_DIR=$(pwd)PREFIX=$SOURCE_DIR/android/$ABI_NAMEecho"=========================================="echo" 编译 FFmpeg for$ABI_NAME"echo"=========================================="cd"$SOURCE_DIR"rm-rf"$PREFIX"makedistclean2>/dev/null||true./configure\--prefix=$PREFIX\--target-os=android\--arch=$ARCH\--cpu=$CPU\--enable-cross-compile\--cross-prefix=$TOOLCHAIN/bin/llvm-\--cc=$TOOLCHAIN/bin/${TOOLCHAIN_ARCH}${API}-clang\--cxx=$TOOLCHAIN/bin/${TOOLCHAIN_ARCH}${API}-clang++\--ar=$TOOLCHAIN/bin/llvm-ar\--nm=$TOOLCHAIN/bin/llvm-nm\--strip=$TOOLCHAIN/bin/llvm-strip\--ranlib=$TOOLCHAIN/bin/llvm-ranlib\--sysroot=$SYSROOT\--enable-shared\--disable-static\--disable-doc\--disable-programs\--enable-network\--enable-jni\--enable-mediacodec\--disable-asmmake-j$(nproc2>/dev/null||echo8)makeinstallecho""echo"?$ABI_NAME编译完成:$PREFIX"ls-la$PREFIX/lib3.2 build_arm64_v8a.sh
#!/bin/bash# =========================================# FFmpeg for Android - arm64-v8a# =========================================set-e# ---------- 配置 ----------exportANDROID_NDK_ROOT=/e/Android/android-sdk/ndk/27.2.12479018API=28ABI_NAME="arm64-v8a"ARCH="aarch64"CPU="armv8-a"TOOLCHAIN_ARCH="aarch64-linux-android"# 判断主机平台case"$(uname-s)"inMINGW*|MSYS*|CYGWIN*)HOST_TAG=windows-x86_64;;Linux*)HOST_TAG=linux-x86_64;;*)echo"不支持的主机平台";exit1;;esacTOOLCHAIN=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/$HOST_TAGSYSROOT=$TOOLCHAIN/sysrootSOURCE_DIR=$(pwd)PREFIX=$SOURCE_DIR/android/$ABI_NAMEecho"=========================================="echo" 编译 FFmpeg for$ABI_NAME"echo"=========================================="echo"NDK:$ANDROID_NDK_ROOT"echo"API:$API"echo"输出:$PREFIX"echo"=========================================="# ---------- 清理 ----------cd"$SOURCE_DIR"rm-rf"$PREFIX"makedistclean2>/dev/null||true# ---------- 配置 ----------./configure\--prefix=$PREFIX\--target-os=android\--arch=$ARCH\--cpu=$CPU\--enable-cross-compile\--cross-prefix=$TOOLCHAIN/bin/llvm-\--cc=$TOOLCHAIN/bin/${TOOLCHAIN_ARCH}${API}-clang\--cxx=$TOOLCHAIN/bin/${TOOLCHAIN_ARCH}${API}-clang++\--ar=$TOOLCHAIN/bin/llvm-ar\--nm=$TOOLCHAIN/bin/llvm-nm\--strip=$TOOLCHAIN/bin/llvm-strip\--ranlib=$TOOLCHAIN/bin/llvm-ranlib\--sysroot=$SYSROOT\--enable-shared\--disable-static\--disable-doc\--disable-programs\--enable-network\--enable-jni\--enable-mediacodec# ---------- 编译 ----------make-j$(nproc2>/dev/null||echo8)makeinstallecho""echo"?$ABI_NAME编译完成:$PREFIX"ls-la$PREFIX/lib赋予执行权限并运行:
# 4. 首次使用前赋权chmod+x build_*.sh# 5. 编译 arm64-v8a./build_arm64_v8a.sh# 6. 编译其他架构(可选)./build_armv7.sh ./build_x86.sh ./build_x86_64.sh编译成功后,库文件位于
./android/aarch64/。
NDK r26+ 注意:
--cross-prefix必须为llvm-,编译器名格式为aarch64-linux-android28-clang。显式指定--android-api可避免 “Defaulting to target API 21” 警告。
四、复制库文件到 Qt 项目
将编译生成的include和lib目录复制到 Qt 项目下:
text
D:\Desktop\WifiUAV_MY\WifiUAV_MY\libs\android\arm64-v8a\ ├── include\ │ ├── libavcodec\ │ ├── libavformat\ │ ├── libavutil\ │ └── libswscale\ └── lib\ ├── libavcodec.so ├── libavcodec.so.61 ├── libavformat.so ├── libavformat.so.61 ├── libavutil.so ├── libavutil.so.59 ├── libswscale.so └── libswscale.so.8重要:
.so和.so.xx软链接指向的实际文件都要复制,缺一不可
五、修改.pro文件
不要使用 $$ANDROID_ABI(它在 qmake 解析阶段为空),直接硬编码arm64-v8a:
增加自行匹配
# 2. 区分平台配置android{FFMPEG_DIR=$$PWD/libs/android# 根据目标 ABI 选择对应的 FFmpeg 库contains(ANDROID_TARGET_ARCH, arm64-v8a){FFMPEG_ANDROID_DIR=$$FFMPEG_DIR/arm64-v8a}contains(ANDROID_TARGET_ARCH, armeabi-v7a){FFMPEG_ANDROID_DIR=$$FFMPEG_DIR/armeabi-v7a}contains(ANDROID_TARGET_ARCH, x86){FFMPEG_ANDROID_DIR=$$FFMPEG_DIR/x86}contains(ANDROID_TARGET_ARCH, x86_64){FFMPEG_ANDROID_DIR=$$FFMPEG_DIR/x86_64}# 兜底:如果没匹配到,默认用 arm64isEmpty(FFMPEG_ANDROID_DIR){FFMPEG_ANDROID_DIR=$$FFMPEG_DIR/arm64-v8a message("Warning: Unknown ABI, fallback to arm64-v8a")}INCLUDEPATH+=$$FFMPEG_ANDROID_DIR/include LIBS+=-L$$FFMPEG_ANDROID_DIR/lib\-lavcodec-lavformat-lavutil-lswscale}else:win32{# Windows 平台:使用项目内置的 Windows FFmpegFFMPEG_DIR=$$PWD/lib/ffmpeg INCLUDEPATH+=$$FFMPEG_DIR/include LIBS+=-L$$FFMPEG_DIR/lib\-lavcodec\-lavformat\-lavutil\-lswscale}else:unix{# Linux/Ubuntu 平台:使用系统 FFmpeg 开发包CONFIG+=link_pkgconfig PKGCONFIG+=libavcodec libavformat libavutil libswscale}修改后执行:清理项目 → 执行 qmake → 重新构建。