前言
本文基于 FFmpeg 5.1.4 版本,詳細(xì)講述了使用 Android.bp 構(gòu)建 FFmpeg 庫的過程,旨在簡化 Android 源碼中 FFmpeg 庫的構(gòu)建以及集成過程。
- 構(gòu)建過程需使用 NDK 工具輔助,請(qǐng)參考該專欄之前文章:使用 NDK 編譯 FFmpeg
- github 倉庫:FFmpegDroidBuilder
搭建編譯框架
以編譯 libavutil、libavcodec、libavformat、libswresample、libswscale 模塊為例,在 FFmpeg 源碼根目錄下,創(chuàng)建以下 7 個(gè)文件:
Android.bp
├── compat_files.bp
├── avutil_files.bp
├── avcodec_files.bp
├── avformat_files.bp
├── swresample_files.bp
└── swscale_files.bp
Android.bp 作為編譯入口,定義整體編譯架構(gòu),其余 6 個(gè) bp 文件作為 Android.bp 的依賴項(xiàng),聲明 FFmpeg 各模塊需編譯的源文件:
- compat_files.bp 聲明 compat 目錄下需編譯的源碼文件,該目錄中存在很多為兼容各種平臺(tái)而創(chuàng)建的頭文件
- 其他 bp 文件則分別聲明 libavutil、libavcodec、libavformat、libswresample、libswscale 目錄下需編譯的源文件
1. 創(chuàng)建 Android.bp 文件
首先,搭建整體編譯框架,后續(xù)章節(jié)再補(bǔ)充具體編譯參數(shù)。
// 依賴項(xiàng)
build = [
"compat_files.bp",
"avutil_files.bp",
"avcodec_files.bp",
"avformat_files.bp",
"swresample_files.bp",
"swscale_files.bp",
]
// 編譯選項(xiàng)默認(rèn)值
cc_defaults {
name: "libFFmpeg_defaults",
cflags: [
],
arch: {
arm: {
cflags: [
],
asflags: [
],
},
arm64: {
cflags: [
],
asflags: [
],
},
},
}
cc_library {
name: "libFFmpeg",
defaults: ["libFFmpeg_defaults"],
local_include_dirs: [
],
vendor_available: true,
export_include_dirs: [
".",
],
// android 10 平臺(tái)需設(shè)置該選項(xiàng)為 false 以停用 XOM
// xom: false,
// 默認(rèn)同時(shí)編譯 32 和 64 位的代碼。若放開下列注釋,則只編譯 64 位的代碼
// compile_multilib: "64",
arch: {
arm: {
instruction_set: "arm",
srcs: [
":avutil-src-arm",
":avcodec-src-arm",
":swresample-src-arm",
":swrscale-src-arm",
],
// ARM 架構(gòu)編譯選項(xiàng)
cflags: [
],
// ARM 架構(gòu)鏈接選項(xiàng)
ldflags: [
],
// ARM 架構(gòu)匯編選項(xiàng)
asflags: [
]
},
arm64: {
srcs: [
":avutil-src-arm64",
":avcodec-src-arm64",
":swresample-src-arm64",
":swrscale-src-arm64",
],
// ARM64 架構(gòu)編譯選項(xiàng)
cflags: [
],
// ARM64 架構(gòu)鏈接選項(xiàng)
ldflags: [
],
// ARM64 架構(gòu)匯編選項(xiàng)
asflags: [
],
},
},
srcs: [
":compat-src",
":avutil-src-common",
":avcodec-src-common",
":swresample-src-common",
":swrscale-src-common",
":avformat-src",
],
shared_libs: [
],
static_libs: [
],
// 全局編譯選項(xiàng)
cflags: [
],
// 全局鏈接選項(xiàng)
ldflags: [
],
// 全局匯編選項(xiàng)
asflags: [
],
}
-
XOM 官當(dāng)說明:AArch64 二進(jìn)制文件的只執(zhí)行內(nèi)存 (XOM)
-
Android.bp 中定義的模塊間依賴關(guān)系如下:
Android.bp
└── libFFmpeg
├── libFFmpeg_defaults
│
├── compat-src
│
├── avutil-src-common
├── avutil-src-arm
├── avutil-src-arm64
│
├── avcodec-src-common
├── avcodec-src-arm
├── avcodec-src-arm64
│
├── swresample-src-common
├── swresample-src-arm
├── swresample-src-arm64
│
├── swrscale-src-common
├── swrscale-src-arm
├── swrscale-src-arm64
│
└── avformat-src
2. 創(chuàng)建 avutil_files.bp
聲明 avutil-src-arm、avutil-src-arm64、avutil-src-common 模塊,后續(xù)章節(jié)再補(bǔ)充這些模塊所依賴的源文件。
filegroup {
name: "avutil-src-arm",
// ARM 架構(gòu)代碼
srcs: [
],
}
filegroup {
name: "avutil-src-arm64",
// ARM64 架構(gòu)代碼
srcs: [
],
}
filegroup {
name: "avutil-src-common",
// 多平臺(tái)共用代碼
srcs: [
],
}
3. 創(chuàng)建其他 bp 文件
參考 avutil_files.bp,創(chuàng)建 compat_files.bp、avcodec_files.bp、avformat_files.bp、swresample_files.bp、swscale_files.bp 文件,并添加相應(yīng)的模塊聲明。
- compat_files.bp
filegroup {
name: "compat-src",
// 無需區(qū)分 ARM 和 ARM64 架構(gòu)
srcs: [
],
}
- avcodec_files.bp
filegroup {
name: "avcodec-src-arm",
// ARM 架構(gòu)代碼
srcs: [
],
}
filegroup {
name: "avcodec-src-arm64",
// ARM64 架構(gòu)代碼
srcs: [
],
}
filegroup {
name: "avcodec-src-common",
// 多平臺(tái)共用代碼
srcs: [
],
}
- avformat_files.bp
filegroup {
name: "avformat-src",
srcs: [
]
}
- swresample_files.bp
filegroup {
name: "swresample-src-arm",
// ARM 架構(gòu)代碼
srcs: [
],
}
filegroup {
name: "swresample-src-arm64",
// ARM64 架構(gòu)代碼
srcs: [
],
}
filegroup {
name: "swresample-src-common",
// 多平臺(tái)共用代碼
srcs: [
],
}
- swscale_files.bp
filegroup {
name: "swrscale-src-arm",
// ARM 架構(gòu)代碼
srcs: [
],
}
filegroup {
name: "swrscale-src-arm64",
// ARM64 架構(gòu)代碼
srcs: [
],
}
filegroup {
name: "swrscale-src-common",
// 多平臺(tái)共用代碼
srcs: [
],
}
armv8-a 編譯參數(shù)
1. configure 源代碼
cpu 架構(gòu)配置為 armv8-a,參考專欄之前的文章:使用 NDK 編譯 FFmpeg。
2. 查看編譯參數(shù)
configure 指令執(zhí)行完成后,在生成的 ffbuild/config.mak 文件中,可查看編譯過程各階段所需參數(shù):
CPPFLAGS:預(yù)處理標(biāo)志
CFLAGS:C編譯標(biāo)志
CXXFLAGS:C++編譯標(biāo)志
ASFLAGS:匯編標(biāo)志
LDFLAGS:鏈接標(biāo)志
LDEXEFLAGS:用于鏈接可執(zhí)行文件的標(biāo)志
3. 添加編譯參數(shù)
前一小節(jié) CPPFLAGS、CFLAGS、CXXFLAGS 中的 flags 可分為以下兩類:
- cpu 特定 flags:如 -mfpu=neon、-march=armv8-a
- 多平臺(tái)共用 flags:如 -fPIC、-fPIE
FFmpeg 源碼根目錄下,執(zhí)行 vim find_flags.sh
編輯腳本文件,用于查找 ffbuild/config.mak 中的編譯參數(shù):
#!/bin/bash
#if [ "$#" -ne 1 ]; then
# echo "Usage: $0 config_file"
# exit 1
#fi
# 獲取配置文件
#config_file=$1
config_file=ffbuild/config.mak
# 定義需要查找的變量
vars=("CPPFLAGS" "CFLAGS" "CXXFLAGS" "ASFLAGS" "LDFLAGS")
# 定義需打印的 cpu 特定參數(shù)
cpu_specific_prefixes=("-mfpu" "-march")
# 定義需要過濾的標(biāo)志
filter_prefixes=("CPPFLAGS" "CFLAGS" "CXXFLAGS" "ASFLAGS" "LDFLAGS" "--sysroot" "-mfpu" "-march" "-Wl,-rpath-link")
print_flags() {
# 將參數(shù)轉(zhuǎn)換為數(shù)組
local -a local_filter_prefixes="($(echo "$1"))"
local local_should_print=$2
local var_prefix=$3
for var in "${vars[@]}"; do
flags=$(grep "^$var" "$config_file")
# 分割參數(shù)
IFS=' ' read -r -a flagarray <<< "$flags"
# 過濾重復(fù)參數(shù)參數(shù)
flagarray=($(printf "%s\n" "${flagarray[@]}" | sort -u))
echo "$3_$var: {"
for flag in "${flagarray[@]}"; do
# 檢查參數(shù)是否需要過濾
if [ "$local_should_print" = true ] ; then
should_print=false
else
should_print=true
fi
for prefix in "${local_filter_prefixes[@]}"; do
if [[ "$flag" == $prefix* ]]; then
should_print=$local_should_print
fi
done
# 如果不需要過濾,則打印
if $should_print ; then
echo " \"$flag\","
fi
done
echo "}"
done
}
# 將數(shù)組轉(zhuǎn)換為字符串并傳遞給函數(shù)
print_flags "${filter_prefixes[*]}" false common
echo -e "\n"
print_flags "${cpu_specific_prefixes[*]}" true cpu_specific
執(zhí)行 ./find_flags.sh
指令,查找編譯參數(shù):
common_CPPFLAGS: {
"-D_FILE_OFFSET_BITS=64",
"-D_ISOC99_SOURCE",
"-D_LARGEFILE_SOURCE",
"-DPIC",
"-Dstrtod=avpriv_strtod",
"-DZLIB_CONST",
}
common_CFLAGS: {
"-fno-math-errno",
"-fno-signed-zeros",
"-fomit-frame-pointer",
"-fpic",
"-fPIC",
"-fPIE",
"-g",
"-mno-stackrealign",
"-mstack-alignment=16",
"-Os",
"-Oz",
"-pthread",
"-Qunused-arguments",
"-std=c11",
"-Wall",
"-Wdeclaration-after-statement",
"-Wdisabled-optimization",
"-Wempty-body",
"-Werror=implicit-function-declaration",
"-Werror=missing-prototypes",
"-Werror=return-type",
"-Wmissing-prototypes",
"-Wno-bool-operation",
"-Wno-char-subscripts",
"-Wno-format-zero-length",
"-Wno-parentheses",
"-Wno-pointer-sign",
"-Wno-switch",
"-Wno-unused-const-variable",
"-Wpointer-arith",
"-Wredundant-decls",
"-Wstrict-prototypes",
"-Wtype-limits",
"-Wundef",
"-Wwrite-strings",
}
common_CXXFLAGS: {
"-D__STDC_CONSTANT_MACROS",
"-std=c++11",
}
common_ASFLAGS: {
"-fpic",
"-fPIC",
"-g",
"-mno-stackrealign",
"-Os",
"-Qunused-arguments",
}
common_LDFLAGS: {
"-Qunused-arguments",
"-Wl,--as-needed",
"-Wl,--warn-common",
"-Wl,-z,noexecstack",
}
cpu_specific_CPPFLAGS: {
}
cpu_specific_CFLAGS: {
"-march=armv8-a",
"-mfpu=neon",
}
cpu_specific_CXXFLAGS: {
}
cpu_specific_ASFLAGS: {
"-march=armv8-a",
"-mfpu=neon",
}
cpu_specific_LDFLAGS: {
"-march=armv8-a",
}
將上述 cpu_specific_CPPFLAGS、cpu_specific_CFLAGS、cpu_specific_CXXFLAGS
添加到 Android.bp libFFmpeg 模塊 arm64 cflags 中,common_CPPFLAGS、common_CFLAGS、common_CXXFLAGS
添加到全局編譯選項(xiàng)中:
cc_library {
name: "libFFmpeg",
... 省略部分代碼
arch: {
arm: {
... 省略部分代碼
},
arm64: {
srcs: [
":avutil-src-arm64",
":avcodec-src-arm64",
":swresample-src-arm64",
":swrscale-src-arm64",
],
// ARM64 架構(gòu)編譯選項(xiàng)
cflags: [
"-mfpu=neon",
"-march=armv8-a",
],
// ARM64 架構(gòu)鏈接選項(xiàng)
ldflags: [
],
// ARM64 架構(gòu)匯編選項(xiàng)
asflags: [
],
},
},
... 省略部分代碼
srcs: [
":compat-src",
":avutil-src-common",
":avcodec-src-common",
":swresample-src-common",
":swrscale-src-common",
":avformat-src",
],
// 全局編譯選項(xiàng)
cflags: [
// CPPFLAGS
"-D_FILE_OFFSET_BITS=64",
"-D_ISOC99_SOURCE",
"-D_LARGEFILE_SOURCE",
"-DPIC",
"-Dstrtod=avpriv_strtod",
"-DZLIB_CONST",
// CFLAGS
"-fno-math-errno",
"-fno-signed-zeros",
"-fomit-frame-pointer",
"-fpic",
"-fPIC",
"-fPIE",
"-g",
"-mno-stackrealign",
"-mstack-alignment=16",
"-Os",
"-Oz",
"-pthread",
"-Qunused-arguments",
"-std=c11",
"-Wall",
"-Wdeclaration-after-statement",
"-Wdisabled-optimization",
"-Wempty-body",
"-Werror=implicit-function-declaration",
"-Werror=missing-prototypes",
"-Werror=return-type",
"-Wmissing-prototypes",
"-Wno-bool-operation",
"-Wno-char-subscripts",
"-Wno-format-zero-length",
"-Wno-parentheses",
"-Wno-pointer-sign",
"-Wno-switch",
"-Wno-unused-const-variable",
"-Wpointer-arith",
"-Wredundant-decls",
"-Wstrict-prototypes",
"-Wtype-limits",
"-Wundef",
"-Wwrite-strings",
// CXXFLAGS
"-D__STDC_CONSTANT_MACROS",
"-std=c++11",
],
// 全局鏈接選項(xiàng)
ldflags: [
],
// 全局匯編選項(xiàng)
asflags: [
],
}
4. 添加匯編參數(shù)
上一章節(jié)編譯參數(shù)中的匯編參數(shù),cpu_specific_ASFLAGS
添加到 Android.bp libFFmpeg 模塊 arm64 asflags 中,common_ASFLAGS
添加到全局匯編選項(xiàng)中:
cc_library {
name: "libFFmpeg",
... 省略部分代碼
arch: {
arm: {
... 省略部分代碼
},
arm64: {
... 省略部分代碼
// ARM64 架構(gòu)鏈接選項(xiàng)
ldflags: [
],
// ARM64 架構(gòu)匯編選項(xiàng)
asflags: [
"-march=armv8-a",
"-mfpu=neon",
],
},
},
... 省略部分代碼
// 全局鏈接選項(xiàng)
ldflags: [
],
// 全局匯編選項(xiàng)
asflags: [
"-fpic",
"-fPIC",
"-g",
"-mno-stackrealign",
"-Os",
"-Qunused-arguments",
],
}
5. 添加鏈接參數(shù)
參考前面章節(jié)內(nèi)容,過程不在贅述,部分代碼如下:
cc_library {
name: "libFFmpeg",
... 省略部分代碼
arch: {
arm: {
... 省略部分代碼
},
arm64: {
... 省略部分代碼
// ARM64 架構(gòu)匯編選項(xiàng)
ldflags: [
"-march=armv8-a",
],
... 省略部分代碼
},
},
... 省略部分代碼
// 全局鏈接選項(xiàng)
ldflags: [
"-Qunused-arguments",
"-Wl,--as-needed",
"-Wl,--warn-common",
"-Wl,-z,noexecstack",
],
... 省略部分代碼
}
6. HAVE_AV_CONFIG_H 參數(shù)
FFmpeg 源碼執(zhí)行完 configure 指定后,根目錄下會(huì)生成一個(gè) config.h 文件。該文件包含了編譯 FFmpeg 時(shí)配置的所有配置選項(xiàng)。config.h 文件中的每個(gè)宏都代表一個(gè)特定的配置選項(xiàng),例如是否啟用某個(gè)庫(如 libavcodec、libavformat 等),是否啟用某個(gè)功能(如硬件加速),以及一些特定的編譯選項(xiàng)(如優(yōu)化級(jí)別、調(diào)試選項(xiàng)等)。
FFmpeg 源碼編譯時(shí),會(huì)根據(jù) HAVE_AV_CONFIG_H 宏來確認(rèn)是否引用 config.h 文件,如 libavutil/bswap.h 中的代碼:
#ifdef HAVE_AV_CONFIG_H
#include "config.h"
#endif
因此我們需要將 -DHAVE_AV_CONFIG_H 添加到編譯選項(xiàng)中。在 Android.bp 文件中,我們將該選項(xiàng)添加到 libFFmpeg_defaults 模塊:
// 編譯選項(xiàng)默認(rèn)值
cc_defaults {
name: "libFFmpeg_defaults",
cflags: [
"-DHAVE_AV_CONFIG_H",
],
... 省略部分代碼
}
armv7-a 編譯參數(shù)
1. 查看編譯參數(shù)
參考前面章節(jié) armv8-a 編譯參數(shù)查找流程:
- configure FFmpeg 源代碼,指定 cpu 架構(gòu)為 armv8-a
- 使用 find_flags.sh 腳本查找編譯參數(shù)
首先,比較 armv7-a 和 armv8-a 編譯參數(shù)差異:
- 編譯參數(shù)差異
- 匯編參數(shù)差異
- cpu 特定參數(shù)差異
2. 添加編譯、匯編、鏈接參數(shù)
根據(jù)上一章節(jié) armv7-a 和 armv8-a 編譯參數(shù)差異,兩種 cpu 架構(gòu)絕大部分編譯參數(shù)可復(fù)用,我們僅需將上述 armv7-a 特定參數(shù)添加到 Android.bp arm 架構(gòu)特定編譯選項(xiàng)中:
cc_library {
name: "libFFmpeg",
... 省略部分代碼
arch: {
arm: {
instruction_set: "arm",
... 省略部分代碼
// ARM 架構(gòu)編譯選項(xiàng)
cflags: [
"-marm",
"-mfloat-abi=softfp",
"-march=armv7-a",
"-mfpu=neon",
],
// ARM 架構(gòu)鏈接選項(xiàng)
ldflags: [
"-march=armv7-a",
],
// ARM 架構(gòu)匯編選項(xiàng)
asflags: [
"-mfloat-abi=softfp",
"-march=armv7-a",
"-mfpu=neon",
]
},
},
... 省略部分代碼
}
添加 armv8-a 源文件
首先,我們需要使用 NDK 對(duì)源碼進(jìn)行編譯,參考專欄之前的文章:使用 NDK 編譯 FFmpeg 。然后根據(jù)編譯后的 .o 目標(biāo)文件,從源碼中匹配對(duì)應(yīng)的源文件(.c 或 .S 文件)。
1. 查找需編譯的源文件
配置 cpu 架構(gòu)為 armv8-a,并編譯 FFmpeg 源代碼。然后,在 FFmpeg 源碼目錄下,執(zhí)行 vim find_srcs.sh
,編輯腳本文件如下:
#!/bin/bash
# 打印幫助提示
if [ "$#" -eq 0 ] || [ "$1" == "-h" ] || [ "$1" == "--help" ]; then
echo "Usage: $0 dir1 [dir2 ...]"
echo "Example: $0 libavutil libavutil/aarch64"
exit 0
fi
# 定義查找源文件的函數(shù)
findSrc() {
local dir=$1
local f=`ls $dir/*.o 2>/dev/null`
echo "$dir: {"
for d in $f
do
local s=${d//.o/.c}
if [ -f "$s" ]; then
echo " \"${d//.o/.c}\","
else
echo " \"${d//.o/.S}\","
fi
done
echo "}"
}
# 遍歷每個(gè)參數(shù)并查找源文件
for dir in "$@"; do
echo "Source files in $dir:"
findSrc $dir
done
在源碼目錄下執(zhí)行該腳本,查找需編譯的源文件,示例如下:
- 執(zhí)行
./find_srcs.sh compat
,查找 compat 目錄
Source files in compat:
compat: {
"compat/strtod.c",
}
- 執(zhí)行
./find_srcs.sh libavutil libavutil/aarch64
,查找 libavutil、libavutil/aarch64 目錄
Source files in libavutil:
libavutil: {
"libavutil/adler32.c",
"libavutil/aes_ctr.c",
"libavutil/aes.c",
"libavutil/audio_fifo.c",
"libavutil/avsscanf.c",
"libavutil/avstring.c",
"libavutil/base64.c",
"libavutil/blowfish.c",
"libavutil/bprint.c",
"libavutil/buffer.c",
"libavutil/camellia.c",
"libavutil/cast5.c",
"libavutil/channel_layout.c",
"libavutil/color_utils.c",
"libavutil/cpu.c",
"libavutil/crc.c",
"libavutil/csp.c",
"libavutil/des.c",
"libavutil/detection_bbox.c",
"libavutil/dict.c",
"libavutil/display.c",
"libavutil/dovi_meta.c",
"libavutil/downmix_info.c",
"libavutil/encryption_info.c",
"libavutil/error.c",
"libavutil/eval.c",
"libavutil/fifo.c",
"libavutil/file.c",
"libavutil/file_open.c",
"libavutil/film_grain_params.c",
"libavutil/fixed_dsp.c",
"libavutil/float_dsp.c",
"libavutil/frame.c",
"libavutil/hash.c",
"libavutil/hdr_dynamic_metadata.c",
"libavutil/hdr_dynamic_vivid_metadata.c",
"libavutil/hmac.c",
"libavutil/hwcontext.c",
"libavutil/hwcontext_stub.c",
"libavutil/imgutils.c",
"libavutil/integer.c",
"libavutil/intmath.c",
"libavutil/lfg.c",
"libavutil/lls.c",
"libavutil/log2_tab.c",
"libavutil/log.c",
"libavutil/lzo.c",
"libavutil/mastering_display_metadata.c",
"libavutil/mathematics.c",
"libavutil/md5.c",
"libavutil/mem.c",
"libavutil/murmur3.c",
"libavutil/opt.c",
"libavutil/parseutils.c",
"libavutil/pixdesc.c",
"libavutil/pixelutils.c",
"libavutil/random_seed.c",
"libavutil/rational.c",
"libavutil/rc4.c",
"libavutil/reverse.c",
"libavutil/ripemd.c",
"libavutil/samplefmt.c",
"libavutil/sha512.c",
"libavutil/sha.c",
"libavutil/slicethread.c",
"libavutil/spherical.c",
"libavutil/stereo3d.c",
"libavutil/tea.c",
"libavutil/threadmessage.c",
"libavutil/timecode.c",
"libavutil/time.c",
"libavutil/tree.c",
"libavutil/twofish.c",
"libavutil/tx_double.c",
"libavutil/tx_float.c",
"libavutil/tx_int32.c",
"libavutil/tx.c",
"libavutil/utils.c",
"libavutil/uuid.c",
"libavutil/version.c",
"libavutil/video_enc_params.c",
"libavutil/xga_font_data.c",
"libavutil/xtea.c",
}
Source files in libavutil/aarch64:
libavutil/aarch64: {
"libavutil/aarch64/cpu.c",
"libavutil/aarch64/float_dsp_init.c",
"libavutil/aarch64/float_dsp_neon.S",
}
2. 添加 compat 源文件
編輯 compat_files.bp 文件,添加上一章節(jié)中查找到的 compat 源文件:
filegroup {
name: "compat-src",
srcs: [
"compat/strtod.c",
],
}
3. 添加 libavutil 源文件
編輯 avutil_files.bp 文件,添加上一章節(jié)中查找到的 libavutil 源文件。libavutil/aarch64、libavutil 目錄下源文件分別添加到 avutil-src-arm64、avutil-src-common 目錄下:
filegroup {
name: "avutil-src-arm",
// ARM 架構(gòu)代碼
srcs: [
],
}
filegroup {
name: "avutil-src-arm64",
// ARM64 架構(gòu)代碼
srcs: [
"libavutil/aarch64/cpu.c",
"libavutil/aarch64/float_dsp_init.c",
"libavutil/aarch64/float_dsp_neon.S",
],
}
filegroup {
name: "avutil-src-common",
// 多平臺(tái)共用代碼
srcs: [
"libavutil/adler32.c",
"libavutil/aes_ctr.c",
"libavutil/aes.c",
"libavutil/audio_fifo.c",
"libavutil/avsscanf.c",
"libavutil/avstring.c",
"libavutil/base64.c",
"libavutil/blowfish.c",
"libavutil/bprint.c",
"libavutil/buffer.c",
"libavutil/camellia.c",
"libavutil/cast5.c",
"libavutil/channel_layout.c",
"libavutil/color_utils.c",
"libavutil/cpu.c",
"libavutil/crc.c",
"libavutil/csp.c",
"libavutil/des.c",
"libavutil/detection_bbox.c",
"libavutil/dict.c",
"libavutil/display.c",
"libavutil/dovi_meta.c",
"libavutil/downmix_info.c",
"libavutil/encryption_info.c",
"libavutil/error.c",
"libavutil/eval.c",
"libavutil/fifo.c",
"libavutil/file.c",
"libavutil/file_open.c",
"libavutil/film_grain_params.c",
"libavutil/fixed_dsp.c",
"libavutil/float_dsp.c",
"libavutil/frame.c",
"libavutil/hash.c",
"libavutil/hdr_dynamic_metadata.c",
"libavutil/hdr_dynamic_vivid_metadata.c",
"libavutil/hmac.c",
"libavutil/hwcontext.c",
"libavutil/hwcontext_stub.c",
"libavutil/imgutils.c",
"libavutil/integer.c",
"libavutil/intmath.c",
"libavutil/lfg.c",
"libavutil/lls.c",
"libavutil/log2_tab.c",
"libavutil/log.c",
"libavutil/lzo.c",
"libavutil/mastering_display_metadata.c",
"libavutil/mathematics.c",
"libavutil/md5.c",
"libavutil/mem.c",
"libavutil/murmur3.c",
"libavutil/opt.c",
"libavutil/parseutils.c",
"libavutil/pixdesc.c",
"libavutil/pixelutils.c",
"libavutil/random_seed.c",
"libavutil/rational.c",
"libavutil/rc4.c",
"libavutil/reverse.c",
"libavutil/ripemd.c",
"libavutil/samplefmt.c",
"libavutil/sha512.c",
"libavutil/sha.c",
"libavutil/slicethread.c",
"libavutil/spherical.c",
"libavutil/stereo3d.c",
"libavutil/tea.c",
"libavutil/threadmessage.c",
"libavutil/timecode.c",
"libavutil/time.c",
"libavutil/tree.c",
"libavutil/twofish.c",
"libavutil/tx_double.c",
"libavutil/tx_float.c",
"libavutil/tx_int32.c",
"libavutil/tx.c",
"libavutil/utils.c",
"libavutil/uuid.c",
"libavutil/version.c",
"libavutil/video_enc_params.c",
"libavutil/xga_font_data.c",
"libavutil/xtea.c",
],
}
4. 添加其他模塊源文件
從 ffbuild/config.sh 中查看模塊間依賴關(guān)系:
swscale_deps="avutil"
avformat_deps="avcodec swresample avutil"
avcodec_deps="swresample avutil"
swresample_deps="avutil"
根據(jù)上述依賴關(guān)系依次添加 libswscale、libswresample、libavcodec、libavformat 模塊源文件(參考前面章節(jié)添加 compat 和 libavutil 源文件的過程,本章節(jié)不再贅述)。需要查找的目錄分為以下幾類,完整的 bp 文件請(qǐng)查找后續(xù)章節(jié)代碼倉庫:
- libxxx/arm、libxxx/aarch64:平臺(tái)相關(guān)源文件路徑
- libavxxx、libswxxx:公共源文件路徑
- libxxx/neon:neon 相關(guān)源文件路徑
添加 armv7-a 源文件
除平臺(tái)相關(guān)代碼(位于 libxxx/arm,如 libavtuil/arm),其余代碼可與 armv8-a 復(fù)用。
1. 重新編寫 config.h 文件
為了同時(shí)兼容 armv8-a 和 armv7-a,編譯時(shí)需根據(jù) cpu 架構(gòu),引用不同的 config.h。因此,我們需要重新編寫 config.h 文件:
- 配置 cpu 為 armv8-a,將 config.h 文件重命名為 config_arm64.h
- 執(zhí)行
make clean
,配置 cpu 架構(gòu)為 armv7-a 并重新編譯 FFmpeg 源碼 - 將生成的 config.h 重命名為 config_arm.h
- 對(duì)比 config_arm64.h 和 config_arm.h,發(fā)現(xiàn) config.h 使用了 ARCH_AARCH64 和 ARCH_ARM 來區(qū)分不同的 cpu 架構(gòu)
- 將 ARCH_AARCH64、ARCH_ARM 宏定義移到 Android.bp 的 libFFmpeg_defaults 模塊編譯和匯編選項(xiàng)中
// 編譯選項(xiàng)默認(rèn)值
cc_defaults {
name: "libFFmpeg_defaults",
cflags: [
"-DHAVE_AV_CONFIG_H",
],
arch: {
arm: {
cflags: [
"-DARCH_ARM=1",
"-DARCH_AARCH64=0",
],
asflags: [
"-DARCH_ARM=1",
"-DARCH_AARCH64=0",
],
},
arm64: {
cflags: [
"-DARCH_AARCH64=1",
"-DARCH_ARM=0",
],
asflags: [
"-DARCH_AARCH64=1",
"-DARCH_ARM=0",
],
},
},
}
- 重新創(chuàng)建和編輯 config.h 文件,根據(jù) cpu 架構(gòu)使用不同的配置
#if ARCH_AARCH64
#include "config_arm64.h"
#elif ARCH_ARM
#include "config_arm.h"
#else
#error "Unsupported CPU architecture"
#endif
2. 查找和添加源文件
參考前面 添加 armv8-a 源文件 章節(jié)的內(nèi)容,查找 libavutil/arm、libswscale/arm、libswresample/arm、libavcodec/arm 目錄下 armv7-a 平臺(tái)相關(guān)源文件,并添加到對(duì)應(yīng) bp 文件中,以 libavutil/arm 為例:
- 執(zhí)行
./find_srcs.sh libavutil/arm
,查找 libavutil/arm 目錄下需編譯的源文件
Source files in libavutil/arm:
libavutil/arm: {
"libavutil/arm/cpu.c",
"libavutil/arm/float_dsp_init_arm.c",
"libavutil/arm/float_dsp_init_neon.c",
"libavutil/arm/float_dsp_init_vfp.c",
"libavutil/arm/float_dsp_neon.S",
"libavutil/arm/float_dsp_vfp.S",
}
- 添加源文件到 avutil_files.bp 中
filegroup {
name: "avutil-src-arm",
// ARM 架構(gòu)代碼
srcs: [
"libavutil/arm/cpu.c",
"libavutil/arm/float_dsp_init_arm.c",
"libavutil/arm/float_dsp_init_neon.c",
"libavutil/arm/float_dsp_init_vfp.c",
"libavutil/arm/float_dsp_neon.S",
"libavutil/arm/float_dsp_vfp.S",
],
}
參考上述流程,依次添加源文件到其余 bp 文件,過程不再贅述。完整的 bp 文件請(qǐng)查找后續(xù)章節(jié)代碼倉庫。
編譯錯(cuò)誤處理
- 各模塊中存在一些相同的源文件。如
llibavutil/log2_tab.c
,只能添加在 avutil_files.bp 中,否則會(huì)導(dǎo)致編譯錯(cuò)誤ld.lld: error: duplicate symbol: ff_log2_tab
。使用cat ./libavformat/log2_tab.c
指令,可以發(fā)現(xiàn) libavformat 等模塊其實(shí)是引用了 llibavutil 目錄中的 log2_tab.c 文件,#include "libavutil/log2_tab.c"
./libavformat/log2_tab.c
./libavutil/log2_tab.c
./libavcodec/log2_tab.c
./libswscale/log2_tab.c
./libswresample/log2_tab.c
./libavfilter/log2_tab.c
類似的源文件還有
libavutil/reverse.c
libavcodec/mpegaudiotabs.c
libavcodec/to_upper4.c
libavcodec/mpeg4audio_sample_rates.c
libavcodec/jpegtables.c
libavcodec/ac3_channel_layout_tab.c
libavcodec/dca_sample_rate_tab.c
libavcodec/golomb.c(在 libavformat 中被 libavformat/golomb_tab.c 引用)
- 添加
-Wl,-Bsymbolic
到全局ldflags
中處理以下類型的鏈接錯(cuò)誤,詳細(xì)說明請(qǐng)查閱最后章節(jié)中參考資料
ld.lld: error: relocation R_AARCH64_ADR_PREL_PG_HI21 cannot be used against symbol ff_cos_32; recompile with -fPIC
編譯源代碼
至此,我們已搭建好構(gòu)建 FFmpeg 庫的完整框架,將代碼拷貝到 Android 源碼路徑下,例如:vendor/qcom/packages/apps/ffmpeg-5.1.4,進(jìn)入源碼目錄,執(zhí)行 Android 編譯指令 mma
,即可編譯 FFmpeg 源碼。當(dāng)前代碼已在 Android 10 和 Android 11 平臺(tái)編譯測(cè)試通過。編譯完成后,在 Android 源碼 out 路徑下執(zhí)行 find . -name "libFFmpeg.so"
,即可看到已生成適用于 arm 及 arm64 平臺(tái)的庫文件:
./target/product/msmnile_gvmq/system/product/lib/libFFmpeg.so
./target/product/msmnile_gvmq/system/product/lib64/libFFmpeg.so
./target/product/msmnile_gvmq/system/lib/libFFmpeg.so
./target/product/msmnile_gvmq/system/lib64/libFFmpeg.so
./target/product/msmnile_gvmq/vendor/lib/libFFmpeg.so
./target/product/msmnile_gvmq/vendor/lib64/libFFmpeg.so文章來源:http://www.zghlxwxcb.cn/news/detail-841232.html
整體目錄結(jié)構(gòu)
下圖左側(cè)為 FFmpeg 未修改過的源碼,右側(cè)為修改且 configure 后的源碼:
綠框部分為我們新創(chuàng)建的文件,黃框?yàn)樾薷暮蟮?config.h 配置文件,其余高亮部分由 configure 指令生成文件。文章來源地址http://www.zghlxwxcb.cn/news/detail-841232.html
源碼倉庫
- github 倉庫:FFmpegDroidBuilder
參考資料
- C語言解決動(dòng)態(tài)庫符號(hào)沖突_-wl,-bsymbolic
到了這里,關(guān)于Android.bp 構(gòu)建 FFmpeg 庫:從搭建編譯框架到處理編譯錯(cuò)誤的全過程的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!