編譯ffmpeg支持av1格式
NDK版本:android-ndk-r21e
ffmpeg版本:5.1.8
av1版本:1.2.1
1、先手動編譯av1庫,下面是腳本
!/bin/bash
set -e
set -x
====================== 全局配置 ======================
COMPILE_DIR=/home/linrendi/Desktop/Compile/av1
NDK=/home/linrendi/Desktop/Compile/android-ndk-r21e
DAV1D_VERSION=1.2.1
DAV1D_SRC={DAV1D_VERSION}
LLVM_TOOLCHAIN={NDK}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
GCC_TOOLCHAIN_64=${NDK}/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64
====================== 下載解壓源碼 ======================
cd {DAV1D_VERSION}.tar.bz2" ]; then
wget --no-check-certificate https://code.videolan.org/videolan/dav1d/-/archive/{DAV1D_VERSION}.tar.bz2
fi
if [ ! -d {DAV1D_VERSION}.tar.bz2
fi
cd ${DAV1D_SRC}
====================== 編譯函數(shù) ======================
build_dav1d() {
local ARCH=2 # armv7a-linux-androideabi / aarch64-linux-android
local API={COMPILE_DIR}/dav1d_
4
echo -e "\n========== 編譯 ${ARCH} 架構(gòu) libdav1d =========="
# 清理舊編譯目錄
rm -rf build
# 配置環(huán)境變量
export CC=${LLVM_TOOLCHAIN}/bin/${TARGET}${API}-clang
export CXX=${LLVM_TOOLCHAIN}/bin/${TARGET}${API}-clang++
export AR=${LLVM_TOOLCHAIN}/bin/llvm-ar
export LD=${GCC_TOOLCHAIN}/bin/${TARGET%-linux*}-ld
export STRIP=${LLVM_TOOLCHAIN}/bin/llvm-strip
export PKG_CONFIG_LIBDIR=${INSTALL_DIR}/lib/pkgconfig
# 驗證工具
if [ ! -f "${CC}" ]; then
echo "錯誤:Clang不存在!路徑:${CC}"
exit 1
fi
# 配置meson
meson setup build \
--cross-file <(echo -e "[binaries]\ncc = '${CC}'\ncxx = '${CXX}'\nar = '${AR}'\nld = '${LD}'\nstrip = '${STRIP}'\n[host_machine]\nsystem = 'android'\ncpu_family = '${ARCH%v7a}'\ncpu = '${ARCH}'\nendian = 'little'") \
--prefix=${INSTALL_DIR} \
--libdir=lib \
--buildtype=release \
--default-library=static \
-Denable_asm=false \
-Denable_tools=false \
-Denable_tests=false
# 編譯安裝
ninja -C build install -j4
# 驗證結(jié)果
if [ ! -f "${INSTALL_DIR}/lib/libdav1d.a" ]; then
echo "錯誤:${ARCH} 架構(gòu) libdav1d.a 編譯失敗!"
exit 1
fi
echo "? ${ARCH} 架構(gòu) libdav1d 編譯完成:${INSTALL_DIR}/lib/libdav1d.a"
}
====================== 執(zhí)行編譯 ======================
編譯32位(armeabi-v7a)
build_dav1d "armv7a" "armv7a-linux-androideabi" 21 ${GCC_TOOLCHAIN_32}
編譯64位(arm64-v8a)
build_dav1d "aarch64" "aarch64-linux-android" 21 ${GCC_TOOLCHAIN_64}
echo -e "\n?? 所有架構(gòu) libdav1d 編譯完成!"
echo "32位路徑:{COMPILE_DIR}/dav1d_aarch64"
2、下載ffmpeg 5.1.8版本,ndk21e版本,并解壓,進(jìn)入ffmpeg 5.1.8文件夾,將編譯好的av1庫引用到ffmpeg配置文件里面

3、在ffmpeg 5.1.8文件夾里面創(chuàng)建下面腳本,執(zhí)行
!/bin/bash
set -e
===================== 核心配置(根據(jù)實際路徑修改)=====================
NDK=/home/linrendi/Desktop/Compile/android-ndk-r21e
ROOT_PREFIX=/home/linrendi/Desktop/ffmpeg_android
ANDROID_API=23
JOBS=4
FFMPEG_DIR=$(pwd)
16KB 對齊常量(Android 強(qiáng)制要求)
ALIGNMENT=16384
===================== 架構(gòu)編譯函數(shù) =====================
build_ffmpeg() {
local ARCH=2
local TARGET=4
local SYSROOT=6
local LDFLAGS={ROOT_PREFIX}/${ARCH}
local DAV1D_PATH=/home/linrendi/Desktop/Compile/av1/dav1d_${ARCH}
# ===================== 前置驗證 =====================
if [ ! -f "${DAV1D_PATH}/lib/libdav1d.a" ] || [ ! -d "${DAV1D_PATH}/include/dav1d" ]; then
echo -e "\033[31m【致命錯誤】64位libdav1d不完整!\033[0m"
echo "檢查:1. ${DAV1D_PATH}/lib/libdav1d.a 2. ${DAV1D_PATH}/include/dav1d/dav1d.h"
exit 1
fi
mkdir -p ${PREFIX}
echo "===== 開始編譯 ${ARCH} 架構(gòu) ====="
make clean || true
# 提取架構(gòu)名(arm/arm64)
local ARCH_NAME=$(echo ${ARCH} | cut -d'-' -f1)
# 配置 FFmpeg(適配FFmpeg 5.1.8:移除無效BSF,保留核心解碼功能)
./configure \
--prefix=${PREFIX} \
--target-os=android \
--disable-doc \
--cross-prefix=${TOOLCHAIN}/bin/${TARGET}- \
--arch=${ARCH_NAME} \
--cpu=${CPU} \
--disable-asm \
--sysroot=${SYSROOT} \
--extra-cflags="${CFLAGS} -I${DAV1D_PATH}/include -DDAV1D_API_VERSION=1 -fstack-protector-strong -D_FORTIFY_SOURCE=2 -fPIC -Wformat -Wformat-security -Werror=format-security" \
--extra-ldflags="${LDFLAGS} -L${DAV1D_PATH}/lib -ldav1d -fPIC -Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack -Wl,-z,max-page-size=${ALIGNMENT} -Wl,-z,common-page-size=${ALIGNMENT}" \
--cc=${TOOLCHAIN}/bin/${CLANG_TARGET}${ANDROID_API}-clang \
--cxx=${TOOLCHAIN}/bin/${CLANG_TARGET}${ANDROID_API}-clang++ \
--nm=${TOOLCHAIN}/bin/${TARGET}-nm \
--disable-shared \
--enable-static \
--enable-small \
--disable-debug \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-symver \
--enable-neon \
--enable-pthreads \
--disable-devices \
--disable-encoders \
--enable-decoder=av1,av1_mediacodec \
--enable-hwaccel=av1_mediacodec \
--enable-parser=av1 \
--enable-libdav1d \
--enable-decoder=hevc,hevc_mediacodec \
--enable-hwaccel=hevc_mediacodec \
--enable-hwaccels --enable-jni --enable-mediacodec \
--enable-parser=hevc \
--enable-encoder=aac \
--enable-jni \
--enable-mediacodec \
--enable-encoder=aac \
--enable-decoder=h264_mediacodec \
--enable-hwaccel=h264_mediacodec \
--enable-encoder=mjpeg \
--enable-encoder=ljpeg \
--enable-encoder=jpeg2000 \
--enable-encoder=jpegls \
--enable-muxer=mp4 \
--enable-muxer=mjpeg \
--enable-encoder=ljpeg --enable-encoder=jpeg2000 --enable-encoder=jpegls \
--enable-runtime-cpudetect \
--extra-libs="-lm -lz -ldl -llog -latomic" \
--disable-vulkan \
--disable-bzlib \
--disable-openssl \
--disable-postproc \
--disable-programs \
--disable-hardcoded-tables
if [ $? -ne 0 ]; then
echo "${ARCH} 配置失敗,查看 ffbuild/config.log 了解詳情"
exit 1
fi
# 編譯
make -j${JOBS}
if [ $? -ne 0 ]; then
echo "${ARCH} 編譯失敗"
exit 1
fi
# 安裝靜態(tài)庫
make install
if [ $? -ne 0 ]; then
echo "${ARCH} 安裝失敗"
exit 1
fi
# 鏈接動態(tài)庫(單行命令,無換行)
echo "===== 開始鏈接 ${ARCH} 動態(tài)庫 ====="
if [ "${ARCH}" = "armeabi-v7a" ]; then
${TOOLCHAIN}/bin/${CLANG_TARGET}${ANDROID_API}-clang -fPIE -pie -shared -nostdlib -Bsymbolic --sysroot=${SYSROOT} -march=${CPU} -o ${PREFIX}/libffmpeg.so -Wl,--whole-archive -Wl,-z,max-page-size=${ALIGNMENT} -Wl,-z,common-page-size=${ALIGNMENT} ${DAV1D_PATH}/lib/libdav1d.a libavcodec/libavcodec.a libavfilter/libavfilter.a libswresample/libswresample.a libavformat/libavformat.a libavutil/libavutil.a libswscale/libswscale.a libavdevice/libavdevice.a -Wl,--no-whole-archive -lm -lz -ldl -llog -latomic -lgcc -lc -lm -lstdc++ -Wl,--fix-cortex-a8
else
${TOOLCHAIN}/bin/${CLANG_TARGET}${ANDROID_API}-clang -fPIE -pie -shared -nostdlib -Bsymbolic --sysroot=${SYSROOT} -march=${CPU} -o ${PREFIX}/libffmpeg.so -Wl,--whole-archive -Wl,-z,max-page-size=${ALIGNMENT} -Wl,-z,common-page-size=${ALIGNMENT} ${DAV1D_PATH}/lib/libdav1d.a libavcodec/libavcodec.a libavfilter/libavfilter.a libswresample/libswresample.a libavformat/libavformat.a libavutil/libavutil.a libswscale/libswscale.a libavdevice/libavdevice.a -Wl,--no-whole-archive -lm -lz -ldl -llog -latomic -lgcc -lc -lm -lstdc++
fi
if [ $? -ne 0 ]; then
echo "${ARCH} 鏈接失敗"
exit 1
fi
# ===================== 驗證 =====================
echo -e "\n========================================"
echo -e "\033[32m64位編譯完成!AV1功能驗證\033[0m"
echo -e "========================================"
# 驗證1:AV1核心符號
echo -e "\n【驗證1】AV1解碼符號:"
AV1_SYMBOLS=("av1_decode_frame" "ff_av1_decoder" "dav1d_decode")
for sym in "${AV1_SYMBOLS[@]}"; do
if ${TOOLCHAIN}/bin/llvm-objdump -t ${PREFIX}/libffmpeg.so | grep -q "$sym"; then
echo -e " ? $sym"
else
echo -e " ? $sym"
fi
done
# 驗證2:16KB對齊(關(guān)鍵)
echo -e "\n【驗證2】16KB內(nèi)存對齊:"
ALIGN_CHECK=$(${TOOLCHAIN}/bin/llvm-readelf -l ${PREFIX}/libffmpeg.so | grep "Align" | head -n1 | awk '{print $NF}')
if [ "${ALIGN_CHECK}" = "${ALIGNMENT}" ] || [ "${ALIGN_CHECK}" = "16384" ]; then
echo -e " ? 已滿足Android 16KB對齊要求(當(dāng)前對齊:${ALIGN_CHECK}字節(jié))"
else
echo -e " ? 未滿足16KB對齊!當(dāng)前對齊:${ALIGN_CHECK}字節(jié)(需16384)"
fi
# 優(yōu)化so庫
${TOOLCHAIN}/bin/${TARGET}-strip ${PREFIX}/libffmpeg.so
make clean
echo "===== ${ARCH} 編譯完成!輸出路徑:${PREFIX} ====="
}
===================== 工具鏈基礎(chǔ)配置 =====================
TOOLCHAIN={TOOLCHAIN}/sysroot
===================== 編譯32位(armeabi-v7a)=====================
ARCH=armeabi-v7a
CPU=armv7-a
TARGET=arm-linux-androideabi
CLANG_TARGET=armv7a-linux-androideabi
CFLAGS="-march=armv7-a -mfloat-abi=softfp -mfpu=neon -mthumb -O3 -DANDROID -D__ANDROID_API__={ARCH}
{TARGET}
{SYSROOT} "
{LDFLAGS}"
===================== 編譯64位(arm64-v8a)=====================
ARCH=arm64-v8a
CPU=armv8-a
TARGET=aarch64-linux-android
CLANG_TARGET=aarch64-linux-android
CFLAGS="-march=armv8-a -O3 -DANDROID -D__ANDROID_API__={ARCH}
{TARGET}
{SYSROOT} "
{LDFLAGS}"
echo "===== 所有架構(gòu)編譯完成!根輸出路徑:{ROOT_PREFIX}/armeabi-v7a"
echo "64位輸出:${ROOT_PREFIX}/arm64-v8a"
echo "? 已支持(FFmpeg 5.1.8 兼容版):"
echo " - AV1 軟解(av1)+ 硬解(av1_mediacodec)"
echo " - H.265/HEVC 軟解(hevc)+ 硬解(hevc_mediacodec)"
echo " - H.264 硬解(h264_mediacodec)"