编译针对于Android平台的ffmpeg 4.1版本(最新版)

编译针对于Android平台的ffmpeg 4.1版本(最新版)

前言

如题,本文主要内容是总结在编译FFmpeg过程中遇到一些坑.这里要注意一点是使用不同版本的NDK会遇到对应的不同的坑,这点要注意.本文重点讲编译过程,遇到的坑.关于如何编译,也会略带说点,但是不会说的多仔细,网上关于如何编译的文章,说的也挺多的,流程都差不多,区别也就是configure的配置会因需求而变动等.


编译流程

先大致说下,编译流程,这里为了方便讲解不考虑交叉编译.

  1. 进入FFmpeg官网,或者github上面把源码下载到本地.
    下载地址:
    (1) ffmpeg官网下载地址
    (2)github上FFmpeg的下载地址

  2. 准备好NDK
    去官网下载好ndk,版本的话,推荐r17以下(包括r17c),为什么不用最新版本的r19b呢?这个问题稍后再回答.
    Android NDK 下载地址

  3. 编写build for Android 脚本
    进去FFmpeg目录内,会找到一个configure脚本文件,执行 ./configure --help 命令,你会看到一大串的帮助文档,慢慢看,根据你的项目需要来对编译的FFmpeg进行enable or disable.
    这里要说一点的,如果你想编译FFmpeg动态库的话,就是.so库,需要对configure脚本进行修改.
    修改前:

SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)'
SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR) $(SLIBNAME)'

修改后:

SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'
SLIB_INSTALL_LINKS='$(SLIBNAME)'

修改的目的是为了生成的动态库命名方式可以被Android平台理解,识别.
如果要是编译FFmpeg静态库的话,那就没必要进行上面的修改了.

下面我们在与configure脚本同级目录的地方,创建一个build_android.sh脚本来帮助编译FFmpeg. build_android.sh内容如下:

#!/bin/bash
set -x
API=14
NDK=/NDK安装位置/android-ndk-r15c
SYSROOT=$NDK/platforms/android-$API/arch-arm/
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
function function_one
{
./configure \
  --prefix=$PREFIX \
  --disable-shared \
  --enable-static \
  --disable-doc \
  --disable-ffplay \
  --disable-ffprobe \
  --disable-symver \
  --disable-ffmpeg \
  --cc=$TOOLCHAIN/bin/arm-linux-androideabi-gcc \
  --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
  --target-os=linux \
  --arch=arm \
  --enable-cross-compile \
  --sysroot=$SYSROOT \
  --extra-cflags="-fPIC -DANDROID -D__thumb__ -mthumb -Wfatal-errors -Wno-deprecated -mfloat-abi=softfp -marm -march=armv7-a" \
  --enable-neon

make clean all
make 
make install
}
CPU=armv7-a
PREFIX=$(pwd)/android/$CPU
function_one

现在libavresample 和 libpostproc 默认不启用,已经deprecated,如果想编译这两个库需要设置:
–enable-avresample
–enable-gpl
–enable-nonfree
–enable-postproc
上面的编译脚本编译出来的FFmpeg库还是很完整,挺大的,我们现实项目中一般不需要这么功能齐全,只需要使用其中的部分功能,这里可以根据需要,自行对FFmpeg裁剪,自定义.具体可自定义内容,执行 ./configure.sh --help命令自行查看研究.这里就不细说了.


理想状态下,经过上面的步骤后,会成功的生成android/armv7-a/ 文件,里面会有lib,include目录,lib文件夹里面就是需要的编译好的,适用于Android平台的库文件.
但是往往事实没那么顺利.上面也说了,理想状态下…接下来,坑来了…

在这里插入图片描述


遇到的坑

(一)
上面演示的build_android.sh 脚本中使用的ndk版本是r15c,那在FFmpeg 4.1版本中,你应该会遇到这个error:

libavformat/udp.c: In function 'udp_set_multicast_sources':
libavformat/udp.c:290:28: error: request for member 's_addr' in something not a structure or union

网上很少关于这个错误的描述,官方的回复也没看出来啥子有用的价值.

https://trac.ffmpeg.org/ticket/7741

解决方法:
有两种解决方案
1.ndk版本升到r17c
2.如果不想升ndk版本的,那就修改libavformat/udp.c 文件,把报错的相关代码注释掉就好.前提是你的项目中用不到这块功能.
在低版本的ndk应该都会有这个问题,我有试过r9b版本的,也有这个问题.

(二)
如果使用ndk版本是r17c的话,那上面的问题就不会遇到,但是会遇到新的问题.

CC	libavdevice/alldevices.o
In file included from ./libavformat/internal.h:24:0,
                 from libavdevice/alldevices.c:23:
/opt/andorid_sdk/adt-bundle-linux-x86-20131030/android-ndk-r17c/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/include/stdint.h:9:26: fatal error: stdint.h: No such file or directory

出现这个错误是因为NDK r17c版本将头文件和库文件进行了分离,我们指定的sysroot文件夹下只有库文件,而头文件放在了NDK目录下的sysroot内.
解决方法: 需在–extra-cflags中添加 “-isysroot $NDK/sysroot”

还有有关汇编的头文件也进行了分离.
解决方法:根据目标平台进行指定 “-I$NDK/sysroot/usr/include/arm-linux-androideabi”,将 “arm-linux-androideabi” 改为需要的平台就可以

修改之后的build_android.sh :

#!/bin/bash
set -x
API=14
NDK=/opt/andorid_sdk/adt-bundle-linux-x86-20131030/android-ndk-r17c
SYSROOT=$NDK/platforms/android-$API/arch-arm/
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
function function_one
{
./configure \
  --prefix=$PREFIX \
  --disable-shared \
  --enable-static \
  --disable-doc \
  --disable-ffplay \
  --disable-ffprobe \
  --disable-symver \
  --disable-ffmpeg \
  --cc=$TOOLCHAIN/bin/arm-linux-androideabi-gcc \
  --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
  --target-os=linux \
  --arch=arm \
  --enable-cross-compile \
  --sysroot=$SYSROOT \
  --extra-cflags="-I$NDK/sysroot/usr/include/arm-linux-androideabi -isysroot $NDK/sysroot -fPIC -DANDROID -D__thumb__ -mthumb -Wfatal-errors -Wno-deprecated -mfloat-abi=softfp -marm -march=armv7-a" \
  --enable-neon

make clean all
make 
make install
}
CPU=armv7-a
PREFIX=$(pwd)/android/$CPU
function_one

(三)

libavcodec/aaccoder.c: In function 'search_for_ms':
libavcodec/aaccoder.c:803:25: error: expected identifier or '(' before numeric constant
                     int B0 = 0, B1 = 0;
                         ^

这是由于定义冲突导致的一个error,和ndk
版本有关,我在使用r15c和r9b版本的时候都没有遇到这个问题.
解决方法:修改libavcodec/aaccoder.c 文件 B0改成b0(ps:就是把int型变量名改一下,避免冲突,名字随便起)

(四)

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文件的变量B0改成b0,xB0改成xb0,yB0改成yb0

(五)

libavcodec/opus_pvq.c: In function 'quant_band_template':
libavcodec/opus_pvq.c:498:9: error: expected identifier or '(' before numeric constant
     int B0 = blocks;
         ^

解决方法:将libavcodec/opus_pvq.c文件的变量B0改成b0

结语

除了上面的问题外,中间也遇到过configure.sh脚本没执行成功的问题,原因大都是空格键,一些久的参数过时了,等问题.比如-ffserver这个参数已经不用了.
上面提到说推荐ndk版本是r17c以下的,是因为我们的build_android.sh,编译脚本用用的编译工具是gcc,但是ndk r17c以后的版本,把gcc给移除了.所以如果现在用最新的版本r19b的话,会出现关于gcc的error.考虑更换编译工具不用gcc,应该就能解决问题,但是不知道又会不会出现其他的问题…这个还需要研究,后续有发现,还会持续更新补充.

参考文章

http://alientechlab.com/how-to-build-ffmpeg-for-android/

https://medium.com/@karthikcodes1999/cross-compiling-ffmpeg-4-0-for-android-b988326f16f2

https://blog.csdn.net/luo0xue/article/details/80048847

评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值