此前项目一直使用的 FFmpeg.so 是我从其他团队项目中直接复制过来的,但原来的项目团队不再维护这个库,其中 x264 模块由于一些版权问题需要剔除,所以需要自己重新编译。在编译的过程中踩了很多坑,以及编译 congfigure 有太多的配置,如何减少整体编译出来的大小也是需要花点精力的,本文主要记录编译流程以及相关配置介绍。
编译介绍 自己编译主要参考《一键编译32_64位FFmpeg.4.2.2》 ,最开始的时候自己一直在 Mac M1 上编译,各种流程也是一比一复刻,但是仍然会有各种问题出现,最常见的就是:
aarch64-linux-android21-clang is unable to create an executable file. C compiler test failed.
我反复检查了自己的 NDK 的配置,确保是正确的,文章也有提及处理方式,但是尝试下来都无效,在网上搜了一大篇解决方式,也都无效。不过我看他们很多都是用 Linux 系统进行的编译,遂改为使用 Linux 编译,再重新尝试,似乎没有那些个奇奇怪怪的错误了,也打出了最终的包,最后的 so 大小也符合要求。
编译环境
编译脚本 这是我的一份编译脚本,我的需求是进行本地视频抽帧,所以不需要像滤镜、编码、音频相关的配置,只需要视频解码相关的配置,具体配置在下一节有讲解。
export NDK=.../android-ndk-r20b TOOLCHAIN=$NDK /toolchains/llvm/prebuilt/linux-x86_64 function build_android { ./configure \ --prefix =$PREFIX \ --enable-neon \ --disable-x86asm \ --disable-hwaccels \ --disable-gpl \ --disable-nonfree \ --disable-version3 \ --disable-postproc \ --disable-bsfs \ --disable-protocols \ --enable-protocol =file \ --disable-indevs \ --disable-outdevs \ --disable-debug \ --enable-small \ --enable-jni \ --disable-mediacodec \ --disable-decoder =h264_mediacodec \ --enable-swscale \ --enable-static \ --disable-shared \ --disable-filters \ --disable-avfilter \ --disable-encoders \ --disable-muxers \ --disable-demuxers \ --enable-demuxer =avi \ --enable-demuxer =flv \ --enable-demuxer =h261 \ --enable-demuxer =h263 \ --enable-demuxer =h264 \ --enable-demuxer =hevc \ --enable-demuxer =mov \ --enable-demuxer =m4v \ --disable-decoders \ --enable-decoder =h263 \ --enable-decoder =h263i \ --enable-decoder =h263p \ --enable-decoder =h264 \ --enable-decoder =hevc \ --enable-decoder =flv \ --enable-decoder =mpeg4 \ --disable-parsers \ --enable-parser =h264 \ --enable-parser =h261 \ --enable-parser =h263 \ --enable-parser =mpeg4video \ --enable-parser =mpegvideo \ --disable-htmlpages \ --disable-manpages \ --disable-podpages \ --disable-txtpages \ --disable-vaapi \ --disable-v4l2-m2m \ --disable-nvdec \ --disable-nvenc \ --disable-ffnvcodec \ --disable-dxva2 \ --disable-d3d11va \ --disable-cuvid \ --disable-cuda-llvm \ --disable-cuda-nvcc \ --disable-audiotoolbox \ --disable-amf \ --disable-iconv \ --disable-libxcb \ --disable-libxcb-shm \ --disable-libxcb-xfixes \ --disable-libxcb-shape \ --disable-lzma \ --disable-sdl2 \ --disable-securetransport \ --disable-xlib \ --disable-zlib \ --disable-programs \ --disable-ffmpeg \ --disable-ffplay \ --disable-ffprobe \ --disable-avdevice \ --disable-symver \ --cross-prefix =$CROSS_PREFIX \ --target-os =android \ --arch =$ARCH \ --cpu =$CPU \ --cc =$CC \ --cxx =$CXX \ --enable-cross-compile \ --sysroot =$SYSROOT \ --extra-cflags ="-Os -fpic $OPTIMIZE_CFLAGS " \ --extra-ldflags ="$ADDI_LDFLAGS " make clean make -j16 make install } ARCH=arm64 CPU=armv8-a API=21 CC=$TOOLCHAIN /bin/aarch64-linux-android $API -clang CXX=$TOOLCHAIN /bin/aarch64-linux-android $API -clang ++ SYSROOT=$NDK /toolchains/llvm/prebuilt/linux-x86_64 /sysroot CROSS_PREFIX=$TOOLCHAIN /bin/aarch64-linux-android- PREFIX=$ (pwd )/android/$CPU OPTIMIZE_CFLAGS="-march=$CPU " build_android ARCH=arm CPU=armv7-a API=21 CC=$TOOLCHAIN /bin/armv7a-linux-androideabi $API -clang CXX=$TOOLCHAIN /bin/armv7a-linux-androideabi $API -clang ++ SYSROOT=$NDK /toolchains/llvm/prebuilt/linux-x86_64 /sysroot CROSS_PREFIX=$TOOLCHAIN /bin/arm-linux-androideabi- PREFIX=$ (pwd )/android/$CPU OPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=vfp -marm -march=$CPU " build_android
配置介绍 通过执行 ./configure --help
能得到所有的配置选项,整个配置也非常好理解,通过 list-xxx 可以知道有哪些子选项,然后再通过 --disable-xxx
,或者 --enable-xxx
进行关闭或者打开。以解码为例:
--disable-decoders --enable-decoder =flv --enable-decoder =mpeg4
对于--enable-decoder=xxx
中的xxx可以通过 ./configure --list-decoders
进行查看,同理 encoders
demuxers
muxers
等都是类似的处理,通过 --help
可以通过 list--xxx
查看不同功能的可以支持的配置,主要有以下:
--list-decoders show all available decoders--list-encoders show all available encoders--list-hwaccels show all available hardware accelerators--list-demuxers show all available demuxers--list-muxers show all available muxers--list-parsers show all available parsers--list-protocols show all available protocols--list-bsfs show all available bitstream filters--list-indevs show all available input devices--list-outdevs show all available output devices--list-filters show all available filters
其他的配置就是一些实际性的开关配置,列一些常用的配置:
配置产物为静态库(.a)或者动态库(.so)
--enable-static do not build static libraries [no] --enable-shared build shared libraries [no]
配置减少包大小
--enable-small optimize for size instead of speed
--enable-small
的配置项,其实是在config.h里声称了CONFIG_SMALL选项,然后代码内根据CONFIG_SMALL做了一些调整,比如某些string类型就被省掉了,还有一些内置生成的table, 体积也被裁减掉了,用速度换体积。比如这里:
#if CONFIG_SMALL #define CRC_TABLE_SIZE 257 #else #define CRC_TABLE_SIZE 1024 #endif
配置FFmpeg协议,由于我们使用本地文件,需要再加一个: --enable-protocol=file
,要不然解码会报协议相关错误
--disable-protocols disable all protocols
我们只需要在代码中使用 FFmpeg,所以直接禁用命令行工具
--disable-programs do not build command line programs--disable-ffmpeg disable ffmpeg build--disable-ffplay disable ffplay build--disable-ffprobe disable ffprobe build
还有几个比较重要的就是,主要是
--disable-avdevice disable libavdevice build--disable-swresample disable libswresample build--disable-swscale disable libswscale build--disable-postproc disable libpostproc build--disable-avfilter disable libavfilter build
编译遇见的坑 1、aarch64-linux-android21-clang is unable to create an executable file. C compiler test failed.
这个问题是困扰我最久的,按照解决方法: 原因 1: FFmpeg 4.2.2 版本默认使用了 clang 进行编译 解决:
//1\. 修改 configure 文件 vim configure //2\. 把 默认的 clang 修改为 gcc if test "$target_os" = android; then # cc_default="clang" cc_default="gcc" fi
原因2,检查路径是否正确,主要是 NDK 的位置,以及不同 NDK 相关库可能存在一定的丢失。
这个问题我在 macOS 上未解决,换用 CentOS 没有出现过这个编译问题 。
2、 编译包大小一直不变
最开始我正常编译的时候发现怎么改配置,最后的包大小都没有发生变化,但是命令行里面各种流程又是在走,最终也有产物。这里一定要关注在执行了编译脚本之后,查看最开始的日志,看看具体是一些什么错,这里日志会刷得很快,如果包大小一直没有发生变化的话,可以执行完之后快速停止,看看是什么错。一般就是C compiler test failed.
或者找不到你的配置,改对即可。正常编译,会在开始后列出你的编译配置。
3、x86asm 相关的问题
编译的时候遇到一些 x86asm 的错,按照文章所说即可