1. 環境
1.1 基礎配置
- NDK 22b (r22b)
- FFmpeg 4.4
- Ubuntu 22.04
1.2 下載ffmpeg
官網提供了 .tar.xz
包,可以直接下載解壓:
wget https://ffmpeg.org/releases/ffmpeg-4.4.tar.xz
tar -xvf ffmpeg-4.4.tar.xz
cd ffmpeg-4.4
1.3 安裝基礎工具鏈
sudo apt-get update && sudo apt-get install \
build-essential autoconf automake libtool \
pkg-config cmake git wget unzip yasm
可能不包含全部,遇到報錯缺少的工具鏈的,把報錯拋給AI,按提示下載即可:)
2. 編譯腳本配置
注意將腳本中的 export NDK
換成自己的路徑
#!/bin/bashecho ">>>>>>>>> 編譯硬件解碼版本 <<<<<<<<"#替換為你自己的NDK路徑.export NDK=/home/xaye/Android/Sdk/ndk/android-ndk-r22TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64function build_android{echo "開始編譯 $CPU"./configure \--prefix=$PREFIX \--enable-neon \--enable-hwaccels \--enable-gpl \--enable-postproc \--enable-shared \--disable-debug \--enable-small \--enable-jni \--enable-mediacodec \--enable-decoder=h264_mediacodec \--disable-static \--disable-doc \--enable-ffmpeg \--disable-ffplay \--disable-ffprobe \--disable-avdevice \--disable-doc \--disable-symver \--cross-prefix=$CROSS_PREFIX \--target-os=android \--arch=$ARCH \--cpu=$CPU \--cc=$CC \--cxx=$CXX \--enable-cross-compile \--sysroot=$SYSROOT \--extra-cflags="-Os -fpic $OPTIMIZE_CFLAGS" \--extra-ldflags="$ADDI_LDFLAGS"make cleanmakemake installecho "編譯成功 $CPU"}#armv8-aARCH=arm64CPU=armv8-aAPI=21CC=$TOOLCHAIN/bin/aarch64-linux-android$API-clangCXX=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysrootCROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android-PREFIX=$(pwd)/android/$CPUOPTIMIZE_CFLAGS="-march=$CPU"build_android#armv7-aARCH=armCPU=armv7-aAPI=16CC=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clangCXX=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang++SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysrootCROSS_PREFIX=$TOOLCHAIN/bin/arm-linux-androideabi-PREFIX=$(pwd)/android/$CPUOPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=vfp -marm -march=$CPU "build_android
3. 執行編譯
# 賦予執行權限
chmod +x build_android.sh# 開始編譯(約10-30分鐘)
./build_android.sh
編譯完成后,會生成 android/armv7-a
和 android/armv8-a
目錄,結構如下
android/├── armv7-a/│ ├── lib/*.so│ └── include/ <-- FFmpeg 頭文件└── armv8-a/├── lib/*.so└── include/
這些 .so
文件,分別對應:
armv7-a/
→ 用于 Android 項目的armeabi-v7a
armv8-a/
→ 用于 Android 項目的arm64-v8a
4. Android 項目配置
修改 build.gradle,啟用 NDK 支持
android {defaultConfig {externalNativeBuild {cmake {cppFlags "-std=c++11"abiFilters 'armeabi-v7a', 'arm64-v8a'}}}externalNativeBuild {cmake {path "CMakeLists.txt"}}ndkVersion '22.0.7026061'}
放入頭文件
將 FFmpeg 頭文件復制到 app/src/main/cpp/
下,就是把上面編譯生成的整個 include 文件夾復制進去,不用在意v7a還是v8a,頭文件接口都是一樣的。
創建 CMakeLists.txt
在 app/
目錄下創建:
# 最低 CMake 版本要求
cmake_minimum_required(VERSION 3.4.1)# 項目設置
project("ffmpeg_jni")# 設置 C 標準(FFmpeg 需要 C11)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 11)# 打印當前 ABI 用于調試
message("Current ABI: ${ANDROID_ABI}")# 設置 FFmpeg 庫路徑(根據實際路徑調整)
set(FFMPEG_LIBS_DIR ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI})# 定義 FFmpeg 核心庫(按依賴順序)
set(FFMPEG_LIBSavutilswresampleavcodecavformatswscale# 可選添加其他庫:postproc, avfilter 等
)# 導入預編譯的 FFmpeg 共享庫
foreach(LIB ${FFMPEG_LIBS})add_library(${LIB} SHARED IMPORTED)set_target_properties(${LIB} PROPERTIESIMPORTED_LOCATION "${FFMPEG_LIBS_DIR}/lib${LIB}.so"# 對于 Android 8.0+ 需要設置 SONAMEIMPORTED_SONAME "lib${LIB}.so")message("Imported lib: ${FFMPEG_LIBS_DIR}/lib${LIB}.so")
endforeach()# 添加 Android 日志庫
find_library(log-lib log)# 設置 JNI 源文件
file(GLOB JNI_SOURCES src/main/cpp/*.cpp)# 創建 JNI 庫
add_library(ffmpeg_jni SHARED ${JNI_SOURCES})# 頭文件包含路徑(根據 FFmpeg 頭文件位置調整)
target_include_directories(ffmpeg_jni PRIVATE${CMAKE_SOURCE_DIR}/src/main/cpp/include # 頭文件放在這里${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/include # 如果 FFmpeg 頭文件隨庫提供
)# 鏈接庫
target_link_libraries(ffmpeg_jniandroid${log-lib}${FFMPEG_LIBS} # 按依賴順序自動鏈接
)# 編譯選項優化
target_compile_options(ffmpeg_jni PRIVATE-Wall-Werror-fno-exceptions-fno-rtti-fvisibility=hidden
)
5. JNI 代碼實現
Java 層聲明
創建 FFmpegHelper.java
:
public class FFmpegHelper {static {// 按依賴順序加載FFmpeg庫System.loadLibrary("avutil");System.loadLibrary("swresample");System.loadLibrary("avcodec");System.loadLibrary("avformat");System.loadLibrary("swscale");System.loadLibrary("ffmpeg_jni"); // 我們的JNI庫}public static native String getFFmpegVersion();
}
Native 層實現
創建 ffmpeg_jni.cpp
:
#include <jni.h>
#include <android/log.h>
//#include <libavutil/avutil.h>
#include <stdio.h>extern "C" {
#include <libavutil/avutil.h>
}#define LOG_TAG "FFmpegJNI"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)extern "C" {
JNIEXPORT jstring JNICALL
Java_com_xaye_compiler_FFmpegHelper_getFFmpegVersion(JNIEnv *env, jclass clazz) {// 調用FFmpeg API獲取版本信息const char* version = av_version_info();LOGD("Native FFmpeg version: %s", version);return env->NewStringUTF(version ? version : "Unknown");
}
}
注意:在#include
ffmpeg 庫的頭文件時,要使用 extern "C"
包起來,不然會報錯!
6. 驗證
在主界面 打印版本號
Log.i("MainActivity", " FFmpeg version : "+FFmpegHelper.getFFmpegVersion());
輸出:
代碼已上傳 ffmpeg-compiler
參考:音視頻學習 (六) 一鍵編譯 32/64 位 FFmpeg 4.2.2