- 方案选择
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编译配置:
#!/bin/bash chmod 777 ./configure #chmod 777 ./version.sh NDK=/disk2/wuxingde/android-ndk-r16b SYSROOT=$NDK/platforms/android-27/arch-arm TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64 CROSS=$TOOLCHAIN/bin/arm-linux-androideabi- ISYSROOT=$NDK/sysroot ASM=$ISYSROOT/usr/include/arm-linux-androideabi CC=$TOOLCHAIN/bin/arm-linux-androideabi-gcc NM=$TOOLCHAIN/bin/arm-linux-androideabi-nm CPU=arm PREFIX=./android/$CPU ADDI_CFLAGS="-marm" function build_one { ./configure \ --prefix=$PREFIX \ --target-os=linux \ --arch=$CPU \ --enable-cross-compile \ --incdir=$NDK/sysroot/usr/include \ --sysroot=$SYSROOT \ --cross-prefix=$CROSS \ --cc=$CC \ --nm=$NM \ --extra-cflags="-I$ASM -isysroot $ISYSROOT -Os -fpic $ADDI_CFLAGS" \ --enable-shared \ --enable-static \ --disable-asm \ --enable-pic \ --disable-doc \ --disable-ffmpeg \ --disable-ffplay \ --disable-ffprobe \ --disable-ffserver \ --disable-avdevice \ --disable-doc \ --disable-symver \ --disable-debug \ --disable-encoders \ --disable-muxers \ --enable-avresample \ --disable-pthreads \ --enable-swresample make make install } rm -rf $PREFIX make distclean 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等选项为:
View Code
3. ffmpeg增加动态库导出函数,只需要修改源码所在目录的.v文件,如在libavformat/libavformat.v中增加导出ffurl_register_protocol方法供外部代码链接。
64bit编译配置:
#!/bin/bash chmod 777 ./configure #chmod 777 ./version.sh NDK=/disk2/wuxingde/android-ndk-r16b SYSROOT=$NDK/platforms/android-27/arch-arm64 TOOLCHAIN=$NDK/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64 ISYSROOT=$NDK/sysroot ASM=$ISYSROOT/usr/include/aarch64-linux-android CC=$TOOLCHAIN/bin/aarch64-linux-android-gcc NM=$TOOLCHAIN/bin/aarch64-linux-android-nm CPU=aarch64 PREFIX=$(pwd)/android/$CPU #ADDI_CFLAGS="-marm" function build_one { ./configure \ --prefix=$PREFIX \ --target-os=linux \ --arch=$CPU \ --enable-cross-compile \ --incdir=$NDK/sysroot/usr/include \ --sysroot=$SYSROOT \ --cross-prefix=$TOOLCHAIN/bin/aarch64-linux-android- \ --cc=$CC \ --nm=$NM \ --extra-cflags="-I$ASM -isysroot $ISYSROOT -Os -fpic" \ --enable-shared \ --enable-static \ --enable-asm \ --enable-pic \ --disable-doc \ --disable-ffmpeg \ --disable-ffplay \ --disable-ffprobe \ --disable-ffserver \ --disable-avdevice \ --disable-doc \ --disable-symver \ --disable-debug \ --disable-encoders \ --disable-muxers \ --enable-avresample \ --disable-pthreads \ --enable-swresample make make install } rm -rf $PREFIX make distclean 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=配置,不要随意加额外一些定义,可能会导致链接不上的问题。