Android中集成ffmpeg(一):编译ffmpeg
- 方案选择
Android中集成ffmpeg的codec功能无非两种方式:
- JNI直接调用,主要用于App开发(无权限修改系统底层),如EXOPlayer,JPlayer等。
- 集成ffmpeg到OMX,即封装ffmpeg为OMX的plugin,然后实现component接口。
考虑到性能问题,我选取的方案二即集成ffmpeg到OMX。首先第一个问题就是ffmpeg的编译。也有两种方式:
- 集成ffmpeg源码到整个Android系统工程,独立写bp或mk进行编译。(由于ffmpeg配置复杂,参考网上的一些现成mk进行修改发现工作量比较巨大)
- 独立NDK编译ffmpeg成动态库或静态库,然后通过prebuild的方式集成。(由于OMX的plugin是直接动态加载动态库,无编译上的依赖,此种方法编译跟普通的ffmpeg编译类似,故推荐该方法)
- FFmpeg配置
32bit编译配置:
1 #!/bin/bash 2 3 chmod 777 ./configure 4 #chmod 777 ./version.sh 5 NDK=/your_ndk_path/android-ndk-r16b 6 SYSROOT=$NDK/platforms/android-27/arch-arm 7 TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64 8 CROSS=$TOOLCHAIN/bin/arm-linux-androideabi- 9 10 ISYSROOT=$NDK/sysroot 11 ASM=$ISYSROOT/usr/include/arm-linux-androideabi 12 CC=$TOOLCHAIN/bin/arm-linux-androideabi-gcc 13 NM=$TOOLCHAIN/bin/arm-linux-androideabi-nm 14 15 CPU=arm 16 PREFIX=./android/$CPU 17 ADDI_CFLAGS="-marm" 18 19 function build_one 20 { 21 ./configure \ 22 --prefix=$PREFIX \ 23 --target-os=linux \ 24 --arch=$CPU \ 25 --enable-cross-compile \ 26 --incdir=$NDK/sysroot/usr/include \ 27 --sysroot=$SYSROOT \ 28 --cross-prefix=$CROSS \ 29 --cc=$CC \ 30 --nm=$NM \ 31 --extra-cflags="-I$ASM -isysroot $ISYSROOT -Os -fpic $ADDI_CFLAGS" \ 32 --enable-shared \ 33 --enable-static \ 34 --disable-asm \ 35 --enable-pic \ 36 --disable-doc \ 37 --disable-ffmpeg \ 38 --disable-ffplay \ 39 --disable-ffprobe \ 40 --disable-ffserver \ 41 --disable-avdevice \ 42 --disable-doc \ 43 --disable-symver \ 44 --disable-debug \ 45 --disable-encoders \ 46 --disable-muxers \ 47 --enable-avresample \ 48 --disable-pthreads \ 49 --enable-swresample 50 make 51 make install 52 } 53 54 rm -rf $PREFIX 55 make distclean 56 build_one
说明:
1. --disable-asm选项是因为在ffmpeg-2.0的版本编译出版本运行时出现错误:libavcodec.so: has text relocation。 但是在用ffmpeg-3.3版本时没有出现。也有文章说跟NDK版本也有关系。
可以通过命令检查:readelf -a aarch64/lib/libavcodec.so |grep TEXTREL
2. 在高版本的ffmpeg(如3.3.8)中,可以直接指定--target-os=android ,否则就需要修改configure文件让输出的动态库不带版本号,修改SLIBNAME_WITH_VERSION等选项为:
SLIBNAME='$(SLIBPREF)$(FULLNAME)$(SLIBSUF)' SLIBNAME_WITH_VERSION='$(SLIBNAME).$(LIBVERSION)' 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)'
3. ffmpeg增加动态库导出函数,只需要修改源码所在目录的.v文件,如在libavformat/libavformat.v中增加导出ffurl_register_protocol方法供外部代码链接。
64bit编译配置:
1 #!/bin/bash 2 3 chmod 777 ./configure 4 #chmod 777 ./version.sh 5 NDK=/disk2/wuxingde/android-ndk-r16b 6 SYSROOT=$NDK/platforms/android-27/arch-arm64 7 TOOLCHAIN=$NDK/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64 8 9 ISYSROOT=$NDK/sysroot 10 ASM=$ISYSROOT/usr/include/aarch64-linux-android 11 CC=$TOOLCHAIN/bin/aarch64-linux-android-gcc 12 NM=$TOOLCHAIN/bin/aarch64-linux-android-nm 13 14 CPU=aarch64 15 PREFIX=$(pwd)/android/$CPU 16 #ADDI_CFLAGS="-marm" 17 18 function build_one 19 { 20 ./configure \ 21 --prefix=$PREFIX \ 22 --target-os=linux \ 23 --arch=$CPU \ 24 --enable-cross-compile \ 25 --incdir=$NDK/sysroot/usr/include \ 26 --sysroot=$SYSROOT \ 27 --cross-prefix=$TOOLCHAIN/bin/aarch64-linux-android- \ 28 --cc=$CC \ 29 --nm=$NM \ 30 --extra-cflags="-I$ASM -isysroot $ISYSROOT -Os -fpic" \ 31 --enable-shared \ 32 --enable-static \ 33 --enable-asm \ 34 --enable-pic \ 35 --disable-doc \ 36 --disable-ffmpeg \ 37 --disable-ffplay \ 38 --disable-ffprobe \ 39 --disable-ffserver \ 40 --disable-avdevice \ 41 --disable-doc \ 42 --disable-symver \ 43 --disable-debug \ 44 --disable-encoders \ 45 --disable-muxers \ 46 --enable-avresample \ 47 --disable-pthreads \ 48 --enable-swresample 49 make 50 make install 51 } 52 53 rm -rf $PREFIX 54 make distclean 55 build_one
- PREBUID
如果只用64bit版本可以直接使用下面Android.mk一次性编译:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_PREBUILT_LIBS := \
lib/libavcodec.so \
lib/libavformat.so \
lib/libavutil.so \
lib/libavfilter.so \
lib/libswresample.so \
lib/libavresample.so \
lib/libswscale.so
include $(BUILD_MULTI_PREBUILT)
如果同时需要32bit和64bit版本需要使用下面Android.mk分别编译各个库:
1 LOCAL_PATH := $(call my-dir) 2 include $(CLEAR_VARS) 3 4 LOCAL_SRC_FILES_32 := \ 5 arm/lib/libavcodec.so 6 LOCAL_SRC_FILES_64 := \ 7 aarch64/lib/libavcodec.so 8 LOCAL_MODULE := libavcodec 9 LOCAL_MODULE_SUFFIX := .so 10 LOCAL_MODULE_CLASS := SHARED_LIBRARIES 11 #LOCAL_MODULE_TARGET_ARCH := arm 12 LOCAL_MULTILIB := both 13 include $(BUILD_PREBUILT) 14 15 include $(CLEAR_VARS) 16 LOCAL_SRC_FILES_32 := \ 17 arm/lib/libavformat.so 18 LOCAL_SRC_FILES_64 := \ 19 aarch64/lib/libavformat.so 20 LOCAL_MODULE := libavformat 21 LOCAL_MODULE_SUFFIX := .so 22 LOCAL_MODULE_CLASS := SHARED_LIBRARIES 23 #LOCAL_MODULE_TARGET_ARCH := arm 24 LOCAL_MULTILIB := both 25 include $(BUILD_PREBUILT) 26 27 include $(CLEAR_VARS) 28 LOCAL_SRC_FILES_32 := \ 29 arm/lib/libavutil.so 30 LOCAL_SRC_FILES_64 := \ 31 aarch64/lib/libavutil.so 32 LOCAL_MODULE := libavutil 33 LOCAL_MODULE_SUFFIX := .so 34 LOCAL_MODULE_CLASS := SHARED_LIBRARIES 35 #LOCAL_MODULE_TARGET_ARCH := arm 36 LOCAL_MULTILIB := both 37 include $(BUILD_PREBUILT) 38 39 include $(CLEAR_VARS) 40 LOCAL_SRC_FILES_32 := \ 41 arm/lib/libavresample.so 42 LOCAL_SRC_FILES_64 := \ 43 aarch64/lib/libavresample.so 44 LOCAL_MODULE := libavresample 45 LOCAL_MODULE_SUFFIX := .so 46 LOCAL_MODULE_CLASS := SHARED_LIBRARIES 47 #LOCAL_MODULE_TARGET_ARCH := arm 48 LOCAL_MULTILIB := both 49 include $(BUILD_PREBUILT) 50 51 include $(CLEAR_VARS) 52 LOCAL_SRC_FILES_32 := \ 53 arm/lib/libavfilter.so 54 LOCAL_SRC_FILES_64 := \ 55 aarch64/lib/libavfilter.so 56 LOCAL_MODULE := libavfilter 57 LOCAL_MODULE_SUFFIX := .so 58 LOCAL_MODULE_CLASS := SHARED_LIBRARIES 59 #LOCAL_MODULE_TARGET_ARCH := arm 60 LOCAL_MULTILIB := both 61 include $(BUILD_PREBUILT) 62 63 include $(CLEAR_VARS) 64 LOCAL_SRC_FILES_32 := \ 65 arm/lib/libswresample.so 66 LOCAL_SRC_FILES_64 := \ 67 aarch64/lib/libswresample.so 68 LOCAL_MODULE := libswresample 69 LOCAL_MODULE_SUFFIX := .so 70 LOCAL_MODULE_CLASS := SHARED_LIBRARIES 71 #LOCAL_MODULE_TARGET_ARCH := arm 72 LOCAL_MULTILIB := both 73 include $(BUILD_PREBUILT) 74 75 include $(CLEAR_VARS) 76 LOCAL_SRC_FILES_32 := \ 77 arm/lib/libswscale.so 78 LOCAL_SRC_FILES_64 := \ 79 aarch64/lib/libswscale.so 80 LOCAL_MODULE := libswscale 81 LOCAL_MODULE_SUFFIX := .so 82 LOCAL_MODULE_CLASS := SHARED_LIBRARIES 83 #LOCAL_MODULE_TARGET_ARCH := arm 84 LOCAL_MULTILIB := both 85 include $(BUILD_PREBUILT)
编译部分就到此结束,这部分由于Android NDK版本(我用的是android-ndk-r16b)和ffmpeg版本不同,网上很多教程都没法用,花费了很多时间。特别要注意ffmpeg中--extra-cflags=配置,不要随意加额外一些定义,可能会导致链接不上的问题。