編譯ffmpeg支持av1格式

編譯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={COMPILE_DIR}/dav1d-{DAV1D_VERSION}
LLVM_TOOLCHAIN={NDK}/toolchains/llvm/prebuilt/linux-x86_64 GCC_TOOLCHAIN_32={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 {COMPILE_DIR} if [ ! -f "dav1d-{DAV1D_VERSION}.tar.bz2" ]; then
wget --no-check-certificate https://code.videolan.org/videolan/dav1d/-/archive/{DAV1D_VERSION}/dav1d-{DAV1D_VERSION}.tar.bz2
fi
if [ ! -d {DAV1D_SRC} ]; then tar -xjvf dav1d-{DAV1D_VERSION}.tar.bz2
fi
cd ${DAV1D_SRC}

====================== 編譯函數(shù) ======================

build_dav1d() {
local ARCH=1 # armv7a / aarch64 local TARGET=2 # armv7a-linux-androideabi / aarch64-linux-android
local API=3 # 21(32位)/ 21(64位) local INSTALL_DIR={COMPILE_DIR}/dav1d_{ARCH} local GCC_TOOLCHAIN=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_armv7a" echo "64位路徑:{COMPILE_DIR}/dav1d_aarch64"

2、下載ffmpeg 5.1.8版本,ndk21e版本,并解壓,進(jìn)入ffmpeg 5.1.8文件夾,將編譯好的av1庫引用到ffmpeg配置文件里面


1.png

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=1 local CPU=2
local TARGET=3 local CLANG_TARGET=4
local SYSROOT=5 local CFLAGS=6
local LDFLAGS=7 local PREFIX={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={NDK}/toolchains/llvm/prebuilt/linux-x86_64 SYSROOT={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__={ANDROID_API}" LDFLAGS="-march=armv7-a -Wl,--fix-cortex-a8" build_ffmpeg{ARCH} {CPU}{TARGET} {CLANG_TARGET}{SYSROOT} "{CFLAGS}" "{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__={ANDROID_API}" LDFLAGS="-march=armv8-a" build_ffmpeg{ARCH} {CPU}{TARGET} {CLANG_TARGET}{SYSROOT} "{CFLAGS}" "{LDFLAGS}"

echo "===== 所有架構(gòu)編譯完成!根輸出路徑:{ROOT_PREFIX} =====" echo "32位輸出:{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)"

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容