1. 程式人生 > >Android中整合ffmpeg(一):編譯ffmpeg

Android中整合ffmpeg(一):編譯ffmpeg

  • 方案選擇

Android中整合ffmpeg的codec功能無非兩種方式:

    1. JNI直接呼叫,主要用於App開發(無許可權修改系統底層),如EXOPlayer,JPlayer等。
    2. 整合ffmpeg到OMX,即封裝ffmpeg為OMX的plugin,然後實現component介面。

考慮到效能問題,我選取的方案二即整合ffmpeg到OMX。首先第一個問題就是ffmpeg的編譯。也有兩種方式:

    1. 整合ffmpeg原始碼到整個Android系統工程,獨立寫bp或mk進行編譯。(由於ffmpeg配置複雜,參考網上的一些現成mk進行修改發現工作量比較巨大)
    2. 獨立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
View Code

說明:

 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
View Code

 

  • 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)
View Code

如果同時需要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)
View Code

 

編譯部分就到此結束,這部分由於Android NDK版本(我用的是android-ndk-r16b)和ffmpeg版本不同,網上很多教程都沒法用,花費了很多時間。特別要注意ffmpeg中--extra-cflags=配置,不要隨意加額外一些定義,可能會導致連結不上的問題。