基于ndk-r16b编译Android平台的FFmpeg-3.4.2和FFmpeg-4.0动态库

问题来源

基于NDK编译Android平台的FFmpeg动态库,这件事情我们早在去年就做过了,详细的可以参考我的博文:
https://blog.csdn.net/ericbar/article/details/76602720,
但是FFmpeg的基线版本以及ndk编译链是不断更新的,近期我打算基于最新的FFmpeg版本和ndk版本编译libffmpeg.so时,又遇到了麻烦,各种编译问题。通过这两天的努力,终于编译成功了。于是,打算另起一篇新的文章,将经验和大家分享一下。

FFmpeg版本

从ffmpeg.org官网获知,现在最新的稳定版本分别是FFmpeg 3.4.2 "Cantor"和FFmpeg 4.0 “Wu”,分别下载源码ffmpeg-3.4.2.tar.xz和ffmpeg-4.0.tar.xz,并解压缩到自己的工作目录:

tar xvf ffmpeg-3.4.2.tar.xz
tar xvf ffmpeg-4.0.tar.xz

NDK版本

参考前述博文,在ndk的官方网站(可能需要科学上网)https://developer.android.com/ndk/downloads/index.html 获知最新的ndk稳定版本是r16b,于是下载 android-ndk-r16b-linux-x86_64.zip 并解压,放在 /opt 目录下。

常规办法遇到的问题

参考前述博文,将config.sh的SYSROOT,LIBPATH以及TOOLCHAIN换成对应的r16b版本,如下:

SYSROOT=/opt/android-ndk-r16b/platforms/android-19/arch-arm
LIBPATH=/opt/android-ndk-r16b/platforms/android-19/arch-arm/usr/lib/
TOOLCHAIN=/opt/android-ndk-r16b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/

执行后报错,

ffmpeg@ubuntu:~/work/android/ffmpeg-3.4.2$ ./config.sh 
 
please wait...
 
 
preparing to configure...
 
/opt/android-ndk-r16b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc is unable to create an executable file.
C compiler test failed.

If you think configure made a mistake, make sure you are using the latest
version from Git.  If the latest version fails, report the problem to the
ffmpeg-user@ffmpeg.org mailing list or IRC #ffmpeg on irc.freenode.net.
Include the log file "ffbuild/config.log" produced by configure as this will help
solve the problem.

分析编译链的代码结构,发现android-ndk-r16b\platforms\android-19\arch-arm\usr下只有lib文件夹,没有include文件夹,相关include头文件则位于android-ndk-r16b\sysroot\usr\include下,通过尝试修改
–sysroot=$SYSROOT指向lib路径,并添加配置选项–sysinclude指向include文件夹,configure仍然失败。

正确方法

通过搜索大量的网站,有建议说需要采用standalone的工具链来进行编译,通过尝试获得成功,下面是总结的步骤:

  1. 选择make_standalone_toolchain的方式来制作编译链;
    在刚才下载的android-ndk-r16b\build\tools目录下,有一个Python脚本make_standalone_toolchain.py,通过它可以自动生成我们需要的编译链环境;在此目录下,执行如下命令:
python make_standalone_toolchain.py --api 19 --install-dir /home/ffmpeg/work/toolchain/android/linux-x86_64/ndk-r16/android-19/arm --arch arm --stl libc++ --force

其中,/home/ffmpeg/work/toolchain/android/linux-x86_64/ndk-r16/android-19/arm是我们打算把工具链安装的路径,你可以根据自己需求自定义。另外,我们仍然选择api 19作为我们的编译版本,等待一段时间后,会自动在这个目录下生成完整的编译链,如下图所示:
生成的编译链补充一下,如果是要编译64位的so,API需要大于等于21,所以19是不满足的,其生成指令可以参考如下:

python make_standalone_toolchain.py --api 21 --install-dir /home/ffmpeg/work/toolchain/android/linux-x86_64/ndk-r19c/android-21/arm64 --arch arm64 --stl libc++ --force
  1. 有了正确的编译链后,只需要修改对应的config.sh和make.sh即可,相关目录指向调整如下(参考我的编译链路径):
SYSROOT=/home/ffmpeg/work/toolchain/android/linux-x86_64/ndk-r16/android-19/arm/sysroot
LIBPATH=/home/ffmpeg/work/toolchain/android/linux-x86_64/ndk-r16/android-19/arm/sysroot/usr/lib
TOOLCHAIN=/home/ffmpeg/work/toolchain/android/linux-x86_64/ndk-r16/android-19/arm

3.配置选项调整
从FFmpeg 3.4.2开始,配置选项里的–disable-sdl 需要修改成–disable-sdl2 。对于FFmpeg 4.0,如下几个选项需要去掉,具体变成什么配置,这次暂时不做研究,我只是简单的做了屏蔽处理:

    --disable-ffplay \
    --disable-ffprobe \
    --disable-ffserver \

后期有时间再研究相关配置。
4. 编译问题
事情本来到这里应该很顺利了,但是在编译源码时,遇到莫名其妙的错误:

CC      libavcodec/hevc_filter.o
CC      libavcodec/hevc_mp4toannexb_bsf.o
CC      libavcodec/hevc_mvs.o
libavcodec/hevc_mvs.c: In function 'derive_spatial_merge_candidates':
libavcodec/hevc_mvs.c:208:15: error: 'y0000000' undeclared (first use in this function)
             ((y ## v) >> s->ps.sps->log2_min_pu_size))
               ^
libavcodec/hevc_mvs.c:204:14: note: in definition of macro 'TAB_MVF'
     tab_mvf[(y) * min_pu_width + x]
              ^
libavcodec/hevc_mvs.c:274:16: note: in expansion of macro 'TAB_MVF_PU'
     (cand && !(TAB_MVF_PU(v).pred_flag == PF_INTRA))
                ^
libavcodec/hevc_mvs.c:368:23: note: in expansion of macro 'AVAILABLE'
     is_available_b0 = AVAILABLE(cand_up_right, B0) &&
                       ^
libavcodec/hevc_mvs.c:208:15: note: each undeclared identifier is reported only once for each function it appears in
             ((y ## v) >> s->ps.sps->log2_min_pu_size))
               ^
libavcodec/hevc_mvs.c:204:14: note: in definition of macro 'TAB_MVF'
     tab_mvf[(y) * min_pu_width + x]
              ^
libavcodec/hevc_mvs.c:274:16: note: in expansion of macro 'TAB_MVF_PU'
     (cand && !(TAB_MVF_PU(v).pred_flag == PF_INTRA))
                ^
libavcodec/hevc_mvs.c:368:23: note: in expansion of macro 'AVAILABLE'
     is_available_b0 = AVAILABLE(cand_up_right, B0) &&
                       ^
libavcodec/hevc_mvs.c:207:15: error: 'x0000000' undeclared (first use in this function)
     TAB_MVF(((x ## v) >> s->ps.sps->log2_min_pu_size),                     \

或者是下面这种错误,

libavcodec/aaccoder.c: In function 'search_for_ms':
libavcodec/aaccoder.c:803:25: error: expected identifier or '(' before numeric constant
libavcodec/aaccoder.c:865:28: error: lvalue required as left operand of assignment
libavcodec/aaccoder.c:866:25: error: 'B1' undeclared (first use in this function)
libavcodec/aaccoder.c:866:25: note: each undeclared identifier is reported only once for each function it appears in
ffbuild/common.mak:60: recipe for target 'libavcodec/aaccoder.o' failed
make: *** [libavcodec/aaccoder.o] Error 1

在网上找到大神的解答(http://alientechlab.com/how-to-build-ffmpeg-for-android/),原来是r16b编译链的termbits.h(实际是asm-generic/termbits.h)宏定义了B0,

#define B0 0000000

导致编译链宏定义和局部变量冲突,好大的坑!在编译链头文件里,把这个宏定义语句屏蔽即可。

最后,你应该能顺利的编译出你想要的libffmpeg.so库了。

总结

开源项目给我们带来便利的同时,也给我们带来了不少的坑,填坑是依赖开源项目开发必备的基本技能,但是,只要坚持寻找问题的各种解决办法,总会有柳暗花明的时刻到来。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值