- 方案選擇
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=配置,不要隨意加額外一些定義,可能會導致鏈接不上的問題。
