ffmpeg4.4在Linux下使用android NDK 21新版本编译及其问题解决

一、可参考英文官网
https://trac.ffmpeg.org/wiki/CompilationGuide/Generic
【安装编译、更新、移除】https://trac.ffmpeg.org/wiki/CompilationGuide/Ubuntu#RevertingChangesmadebythisGuide
https://trac.ffmpeg.org/wiki/CompilationGuide
https://trac.ffmpeg.org/

二、下载步骤

备注:可参考官网【安装编译、更新、移除】

安装依赖脚本,并执行它:【若有已安装的可去掉】

sudo apt-get update -qq && sudo apt-get -y install \
  autoconf \
  automake \
  build-essential \
  cmake \
  git-core \
  libass-dev \
  libfreetype6-dev \
  libgnutls28-dev \
  libsdl2-dev \
  libtool \
  libva-dev \
  libvdpau-dev \
  libvorbis-dev \
  libxcb1-dev \
  libxcb-shm0-dev \
  libxcb-xfixes0-dev \
  meson \
  ninja-build \
  pkg-config \
  texinfo \
  wget \
  yasm \
  zlib1g-dev

在自己的home目录中创建:
mkdir -p ~/ffmpeg_sources

然后直接在官网下载最新tar.gzip压缩包版本,放入linux ffmpeg_sources 中解压出来,进入ffmpeg根目录,创建build_android.h,内容如下可参考别人写的利用NDK(r20) 编译FFmpeg 4.2.1 Android版本,也可参考官网自行优化。

但他这边文章有一个错误配置:
如下,即文中的 --arch=arm64 应该写为:–arch=aarch64

–arch=xxx的参数列表在ffbuild/config.log里面会所有支持的arch列表:
ARCH_LIST=’
aarch64
alpha
arm
avr32
avr32_ap
avr32_uc
bfin
ia64
m68k
mips
mips64
parisc
ppc
ppc64
s390
sh4
sparc
sparc64
tilegx
tilepro
tomi
x86
x86_32
x86_64

三、编译步骤
linux版本编译直接参考官网即可:

Linux下必须安装 yasm汇编器【nasm】对ffmpeg中的汇编部分进行编译,默认配置会使用它,否则报错。

ffmpeg源码目录下,首先执行 ./configure ,看是否一切正常,正常将不会报错,还可以看到许多配置信息。
注意修改编译脚本编译结果为so库,而非静态库。

执行上面的编译脚本,等待编译结果在当前目录的android_shared目录中生成。

备注:多核CPU可使用make -j4来提升编译速度,4表示4核。或者使用 make -j$(nproc) 来适配本机可使用的核数

linux版本编译结果时可在最后使用 ffmpeg命令行来验证编译结果,执行 ./ffmpeg.exe -h ,将会出现ffmpeg安装配置信息。

安卓交叉编译:
直接参考别人写的很不错的文章利用NDK(r20) 编译FFmpeg 4.2.1 Android版本

本文主要记录编译错误和运行错误问题

四、编译失败问题
编译时报错:
Makefile执行过程中出错:make: *** No rule to make target ` ‘, needed by xxx. Stop.
需要去掉 --disable-fserver 配置

注意:xxx : command not found
如–disable-doc: command not found 这种指令找不到错误时,就是shell脚本的该行命令上面写了注释但最后用了 \ 反斜杠,必须去掉

错误:
1、libavfilter/af_acrossover.c:42:9: warning: ‘B0’ macro redefined [-Wmacro-redefined]
#define B0 0
改为B00

2、libavfilter/af_aecho.c:188:9: warning: ‘ECHO’ macro redefined [-Wmacro-redefined]
#define ECHO(name, type, min, max)
改为ECHO2

3、若出现WARNING:/root/android-ndk/…/arm-linux-androideabi-pkg-config not found, library detection may fail. 可忽略。

4、ffmpeg库在安卓上运行错误:
java.lang.UnsatisfiedLinkError: dlopen failed: library “libclang_rt.ubsan_standalone-aarch64-android.so” not found。
必须将交叉编译下的该so库拷贝出来和ffmpeg的同CPU库一起加载
至于原因,我也不清楚为啥需要这个独立库?,我也不想要这个库,有同学知道原因还请指出

更新:第4条问题的解决方案只限于不使用Android系统源码来编译的情况,比如使用Android Studio就可以了,但是!!若需要集成到Android系统源码里面进行参与系统源码编译,这会报下面的错误,如下:
build/make/core/base_rules.mk:325: error: external/stagefright-plugins/utils: MODULE.TARGET.SHARED_LIBRARIES.libclang_rt.ubsan_standalone-aarch64-android already defined by prebuilts/clang/host/linux-x86.
由此在这时候我们反而不需要这两个Android so库,我们可以根据编译的版本来链接选用【prebuilts/clang/host/linux-x86】该路径下对应的那个相同文件的so库来预编译,或者在参与安卓源码编译时可以不用编译这两个so都没问题。

5、FAILED: ninja: unknown target 'MODULES-IN-external-xxx
出现该问题时,高版本中没有其它参考文章说的什么顶层Android.bp,根本没有使用这个,由此不是这里的问题,问题是在于我们写的mk文件不符合规范的,多检查下哪里是否多了个反斜杠或者空格啥的。实在不行就可以写一个空项目直接编写mk来测试问题会比较快速。

6、在Android系统源码中集成ffmpeg时,在编写makefile文件时若发生如下错误:
error my-dir must be called before including any other makefile
则表明写的有一个include mk文件放置位置错误,然而有可能并不是英文提示的这个原因,还有另外一个原因,比如此时你希望你当前的mk文件执行时自动执行子目录中的mk文件,那么会如下编写:

# error: my-dir must be called before including any other makefile..
LOCAL_PATH := $(call my-dir)

# 此时就算放在这里也会报上面的错误
# 说明一下该错误的具体原因,即为什么放在这里还会报这个错误,原因就是下面【all-makefiles-under】这一句
# 该句会执行子目录中的mk并加载进来,最终就会导致发现子mk中的【my-dir】刚好就在当前【prebuild_shared.mk】
# 的后面,因此就出现了该错误提示信息!
# This is wrong placed in here!
# It will cause the commend of [all-makefiles-under] occured error.
# include $(LOCAL_PATH)/prebuild_shared.mk

# Target shared library for libffmpeg_utils.so
include $(CLEAR_VARS)

#以此必须放在这里,即CLEAR_VARS里面
# This is right placed in here!
include $(LOCAL_PATH)/prebuild_shared.mk

# 你的当前任务

include $(BUILD_SHARED_LIBRARY)

# 只执行子目录中的Android.mk文件
# Update NOTE: we can use this, but we can not include any other makefiles in this mk.
# FATAL NOTE: the two following commends do not work!!
# Only calling the Android.mk named files under our root path
include $(call all-makefiles-under,$(LOCAL_PATH))
# include $(call all-subdir-makefiles)

7、记录一个非常诡异的问题!!!
问题:android源码编译【BUILD_SHARED_LIBRARY】只编译了32位so库,却始终不能生成64位so库
花费了两三小时时间排查,最终定位到问题第6个问题解决方案中造成的,即这一句:
include $(LOCAL_PATH)/prebuild_shared.mk
它是我ffmpeg的so库预编译专门写的mk文件,因此最终解决方案就是,不能这么引入,直接将它的内容放在上面第6问题的【include $(CLEAR_VARS)】这一句上面即可,但若这样做又会造成第6个问题的产生,所以最终,我直接复制【prebuild_shared.mk】的内容在当前makefile中直接编译,虽然不清楚具体为啥出现这种情况,不过这么做确实解决了,只是这样子当前makefile会有比较多的内容。。。

8、ld.lld: error: undefined symbol: typeinfo for android::SimpleSoftOMXComponent
源码编译时,早前没问题,后来却一直出现没有该头文件引入问题,但仔细检查了头文件依赖和引入头文件路径都正确的,可就是会出现该问题,通过排查makefile文件发现,是后来加入了如下标志【LOCAL_RTTI_FLAG 】导致的,因此去掉即可

# FATAL NOTE: This will cause error, as following:
# ld.lld: error: undefined symbol: typeinfo for android::SimpleSoftOMXComponent
# LOCAL_RTTI_FLAG := -frtti

9、使用Android.bp依赖库头文件编译问题:头文件未找到错误
xxxx.h:11:10: fatal error: ‘utils/xxxx.h’ file not found
方案1:在当前模块依赖的so库bp或者mk配置中,这一句【export_include_dirs】或者【LOCAL_EXPORT_C_INCLUDE】这两个输出的路径就是,当前模块会去自动查找的路径,不必再主动添加。
方案2:当然是可以再次使用include_dirs来主动拉取头文件的,不过这里写的路径就是从root路径开始的。

XXX、随记
2016年初,ffmpeg自身AAC编码器质量变好,年底将此前的libfaac替换为新的自身的libfdkaac,并从源码中移除。
ffmpeg全部支持的话,so库比较大,可以通过裁剪操作来去掉一些不需要的编码、封装或协议等。可以在关闭所有的模块之后单独定制支持自己所需的模块。

“ARMv8-A”是指AArch64,带有A64指令集,也称为arm64或ARM64。

android.mk 和 Makefile中打印变量
$(warning $(DVD_SERVICE)) // DVD_SerVICE是Makefile中的变量

Makefile中宏AS一般代表汇编语言编译器,ASFLAGS一般代表编译汇编语言代码时的编译选项
AS和ASFLAGS都是环境变量。
${xxx}就是取出环境变量的值。
makefile中,AS环境变量一般放的是汇编器的名称,ASFLAGS是汇编参数。
于是
${AS} A S F L A G S 就 是 一 条 用 {ASFLAGS} 就是一条用 ASFLAGS{AS}汇编器传${ASFLAGS}汇编参数的汇编指令,跟上汇编源文件就一条完整的汇编命令语句了。

BUILD_PREBUILT 是预置so到源码指定out目录中,然后成为系统so来访问

而 PREBUILT_SHARED_LIBRARY 却是AS中使用的:NDK 支持使用预编译库
https://www.cnblogs.com/gamesky/p/11369172.html 可参考

shell脚本中打印
echo “canshu2:${analysis_date}”

shell中写的 export命令将变量myfile输出至任何子shell,例如当执行父脚本程序时产生的子shell。
也就是说调用的子shell可以直接使用父shell中变量,所以如果你执行在当前shell中定义变量使用,则不需要写export

你可能感兴趣的:(【ffmpeg】,ffmpeg4.4,android,NDK,21,ubsanstandalone)