基于NDK编译Android平台的FFmpeg动态库
需求
FFmpeg在Linux平臺(如Ubuntu)上的支持已經比較完善了,如前述文章介紹 http://blog.csdn.net/ericbar/article/details/73702061,我們很容易就可以基于FFmpeg+SDL實現一個播放器,比如FFmpeg自帶的ffplay程序,就可以實現音視頻的解碼播放。
現在基于Android手機的媒體應用場景也愈發增多起來,比如流行的直播技術,在終端就用到了音視頻解碼的方法。當然,Android平臺本身提供了java層的MediaPlayer播放器API供調用,但是其靈活性和可定制化程度受到制約,且不便于在其他操作系統(如ios)之間移植,所以我們有必要研究一下FFmpeg在Android平臺的使用移植方法。
首先要完成的工作,就是完成FFmpeg在Android平臺上的編譯,并生成相應的庫。
思路
FFmpeg是基于c語言實現的,所以在Android上只能基于NDK來編譯,網絡上關于如何編譯FFmpeg庫的方法很多,我覺得在參考這些文章的同時,需要堅持幾點方向:
1. 在Ubuntu下編譯;雖然在Windows平臺下也可以實現編譯,但是各種小問題糾纏不清,況且前期我們已經搭建了Ubuntu的環境,所以更加方便;
2. 不用eclipse等工具來編譯,直接基于NDK編譯鏈來進行;
3. 不修改FFmpeg的主要代碼結構,直接依賴代碼原生的Makefile進行;
4. 最終的FFmpeg編譯成一個庫,不再編譯成多個庫(libavformat,libavfilter,libavutil等),所以會有少量的代碼修改;
步驟
NDK編譯鏈下載
首先,下載NDK的Linux版本編譯鏈,地址在https://developer.android.com/ndk/downloads/index.html,可能需要科學上網,當然國內也有很多的下載鏈接,記住一定要下載Linux的版本,由于我們的Ubuntu是64位的,所以我們要下載64位的,現在32位NDK已經不更新和發布了。
寫此文的時候,最新版本的NDK是r14b,所以我們下載android-ndk-r14b-linux-x86_64.zip即可,整個zip包大小在800M左右。
下載完畢后,我們在Ubuntu里解壓縮,得到對應的ndk目錄,把NDK的路徑加到環境變量里即可。
源碼下載
從FFmpeg官方網站下載FFmpeg的源代碼,這里我們仍然以ffmpeg-3.2.4為基礎,從官網下載的包名為ffmpeg-3.2.4.tar.xz,解壓縮代碼得到ffmpeg-3.2.4文件夾。
添加編譯規則
為了基于NDK編譯源碼,網上有很多的方法,包括重新按照代碼目錄建立Android.mk編譯規則,或者大量的修改源代碼,我認為這打亂了FFmpeg本身的代碼結構和Makefile機制,不便于后期版本升級和維護,所以我們這里必須堅持前面“思路”中提到的幾條原則和方向。
為了方便編譯,我們可以通過如下兩個腳本方便的完成動態庫libffmpeg.so的編譯。這兩個腳本分別叫做config.sh和make.sh,其中,config.sh是配置腳本,make.sh是編譯腳本,下面我們來分析這兩個腳本的執行過程,首先分析config.sh,內容如下:
其中,
FFMPEG_SRC_PATH 獲取當前FFmpeg源代碼的路徑,
SYSROOT 為目標系統頭文件和庫所在路徑,我們這里選擇NDK路徑下的相關位置即可,不同版本的NDK其路徑指向可能有差異,但是我們可以通過SYSROOT下的usr包括lib和include兩個目錄來區別。
TOOLCHAIN 為實際的編譯工具鏈路徑,這里選擇4.9版本的64位系統。
PREFIX 指定我們編譯后的文件輸出路徑。
最后的 ./configure 和FFmpeg的標準編譯配置類似,可以根據各自需要調整相應的配置選項。我們這里需要編譯動態庫,所以將如下開關打開–enable-shared。
下面是腳本make.sh的內容:
#!/bin/bash FFMPEG_SRC_PATH=$(cd `dirname $0`; pwd)SYSROOT=/opt/android-ndk-r14b/platforms/android-19/arch-arm LIBPATH=/opt/android-ndk-r14b/platforms/android-19/arch-arm/usr/lib/ TOOLCHAIN=/opt/android-ndk-r14b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/export PATH=$TOOLCHAIN/bin:$PATH export CROSS_PREFIX=arm-linux-androideabi- export CC="$CCACHE ${CROSS_PREFIX}gcc " export CXX=${CROSS_PREFIX}g++ export LD=${CROSS_PREFIX}ld export AR=${CROSS_PREFIX}ar export STRIP=${CROSS_PREFIX}stripLDFLAGS="-lm -lz -Wl,-soname=libffmpeg.so,-z,noexecstack"CPU=arm PREFIX=ffout ADDI_CFLAGS="-marm"#make -j${NUMBER_OF_CORES} && make install || exit 1 make -j16 && make install || exit 1rm libavcodec/reverse.o libavcodec/log2_tab.o libavformat/log2_tab.o libavformat/golomb_tab.o \libswresample/log2_tab.o libavfilter/log2_tab.o libswscale/log2_tab.o$CC -o $PREFIX/libffmpeg.so -shared $LDFLAGS $EXTRA_LDFLAGS --sysroot=$SYSROOT -L $LIBPATH \libavutil/*.o libavutil/arm/*.o libavcodec/*.o libavcodec/arm/*.o \libavformat/*.o libavfilter/*.o libswresample/*.o libswresample/arm/*.o \libswscale/*.o libswscale/arm/*.o compat/*.ocp $PREFIX/libffmpeg.so $PREFIX/libffmpeg-debug.so ${STRIP} --strip-unneeded $PREFIX/libffmpeg.so前面的配置和config.sh類似,make 是編譯,其中j16 可以根據自己機器配置情況進行調整,如果配置并發編譯線程數過多的話,可能會導致編譯錯誤,所以可以將線程數調低再次嘗試。
因為原始的FFmpeg編譯是將多個庫分別編譯得出,而我們這里是將這些庫都打成一個動態庫so,所以如果不做處理的將這些庫鏈接到一起,會出現某些函數重復定義問題,像log2_tab是最常見的,因為這里需要將重復的刪除rm掉,只留下一個過程文件.o即可。
cc是把所有的.o文件打包成so,這里需要注意的是,如果相關目錄下有和cpu相關(比如arm)的子文件夾,則需要將子文件夾的.o也鏈接進來,否則在編譯so庫的時候不會報錯,但是運行程序的時候會找不到相關的函數報錯。
最后的strip是剔除debug信息的ffmpeg庫。
最后,需要注意一下LDFLAGS里的-soname=libffmpeg.so,在早期的Android版本智能手機上運行時,此定義無關緊要,但是在Android 6以后的版本手機上運行時,對so的檢查會更嚴格,如果不加上此項,在運行時可能會報DT_NEEDED的錯誤。
最后,執行make.sh后,會在ffout目錄下生成libffmpeg.so以及相關的庫和頭文件,其中頭文件也是我們后期在Android平臺需要用到的。
接下來,我們便可以在Android平臺編寫基于FFmpeg的應用程序了,比如一個簡單的播放器,我們在接下來的文章中再研究。
總結
以上是生活随笔為你收集整理的基于NDK编译Android平台的FFmpeg动态库的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中职计算机基础知识点笔记3
- 下一篇: 我的Android之路