一、簡介
? ? ? ? FFmpeg既是一款音視頻編解碼工具,同時也是一組音視頻編解碼開發(fā)套件,作為編解碼開發(fā)套件,它為開發(fā)者提供了豐富的音視頻處理的調(diào)用接口。
? ? ? ? FFmpeg提供了多種媒體格式的封裝和解封裝,包括多種音視頻編碼、多種協(xié)議的流媒體、多種色彩格式轉(zhuǎn)換、多種采樣率轉(zhuǎn)換、多種碼率轉(zhuǎn)換等。FFmpeg框架提供了多種豐富的插件模塊,包含封裝與解封裝的插件、編碼與解碼的插件等。
二、編譯環(huán)境
(1) FFmpeg 版本(ffmpeg-4.2.2) 最新
ffmpeg-4.2.2源碼可去FFmpeg官網(wǎng)下載:https://ffmpeg.org/download.html#releases
也可以是用git 直接clone:
git clone "https://git.ffmpeg.org/ffmpeg.git" ffmpeg
(2) NDK版本使用 android-ndk-r17c
去官網(wǎng)下載對應(yīng)的Android NDK:https://developer.android.com/ndk/downloads/older_releases
也可以使用其它版本,但是使用不同版本的NDK來編譯FFmpeg源碼會遇到對應(yīng)的不同的坑,譬如像如下兩個問題:


(3) Linux編譯環(huán)境使用(Ubuntu 14.04 ,x86_64)

三、編譯流程
(1) 修改FFmpeg的configure
? ? ? ? 下載FFmpeg源代碼之后,首先需要對源代碼中的configure文件進(jìn)行修改。由于編譯出來的動態(tài)庫文件名的版本號在.so之后(例如“libavcodec.so.5.100.1”),而android平臺不能識別這樣文件名,所以需要修改這種文件名。在configure文件中找到下面幾行代碼:
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)'
替換為下面內(nèi)容就可以了:
SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'
SLIB_INSTALL_LINKS='$(SLIBNAME)'
(2) 編寫腳本生成類庫
在ffmpeg中創(chuàng)建一個build_android.sh的腳本,并賦予可執(zhí)行的權(quán)限,腳本內(nèi)容如下:
#!/bin/bash
export NDK=/home/startimes/disk6/Android/android-ndk-r17c
export SYSROOT=${NDK}/platforms/android-23/arch-arm
export PREBUILT=${NDK}/toolchains/arm-linux-androideabi-4.9/prebuilt
export PREFIX=./android/arm
function build_so
{
./configure \
--prefix=$PREFIX \
--cross-prefix=${PREBUILT}/linux-x86_64/bin/arm-linux-androideabi- \
--cc=${PREBUILT}/linux-x86_64/bin/arm-linux-androideabi-gcc \
--nm=${PREBUILT}/linux-x86_64/bin/arm-linux-androideabi-nm \
--sysroot=$SYSROOT \
--target-os=android \
--arch=arm \
--enable-shared \
--disable-static \
--enable-cross-compile \
--extra-cflags="-I$NDK/sysroot/usr/include/arm-linux-androideabi -isysroot $NDK/sysroot -fPIC -DANDROID -D__thumb__ -mthumb -Wfatal-errors -Wno-deprecated -mfloat-abi=softfp -marm -march=armv7-a"
}
build_so
make clean
make -j4
make install
其中:
- SYSROOT 為so文件支持的最低Android版本的平臺目錄
- PREFIX 為生成的so文件存放目錄
- cross-prefix 為編譯所使用的工具鏈文件
- target-os 為目標(biāo)操作系統(tǒng)
- enable和disable 指定了需要編譯的項
四、編譯FFmpeg
在ffmpeg目錄下,直接執(zhí)行命令:
./build_android.sh
理想狀態(tài)下,經(jīng)過上面的步驟后,會成功在android/arm/目錄下生成lib,include目錄,lib文件夾里面就是需要的編譯好的、適用于Android平臺的so庫文件。如下圖:

五、編譯問題修改
1)
上面演示的build_android.sh 腳本中使用的ndk版本是r17c,編譯FFmpeg 4.2.2版本你應(yīng)該會遇到如下error:
CC libavdevice/alldevices.o
In file included from ./libavformat/internal.h:24:0,
from libavdevice/alldevices.c:23:
/opt/andorid_sdk/adt-bundle-linux-x86-20131030/android-ndk-r17c/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/include/stdint.h:9:26: fatal error: stdint.h: No such file or directory
出現(xiàn)這個錯誤是因為NDK r17c 版本將頭文件和庫文件進(jìn)行了分離,我們指定的sysroot文件夾下只有庫文件,而頭文件放在了NDK目錄下的sysroot內(nèi);
解決方法: 需在--extra-cflags中添加 “-isysroot $NDK/sysroot”
還有有關(guān)匯編的頭文件也進(jìn)行了分離;
解決方法: 根據(jù)目標(biāo)平臺進(jìn)行指定 “-I$NDK/sysroot/usr/include/arm-linux-androideabi”,將 “arm-linux-androideabi” 改為需要的平臺就可以,此問題上述腳本中已經(jīng)添加完成。
2)
libavcodec/aaccoder.c: In function 'search_for_ms':
libavcodec/aaccoder.c:803:25: error: expected identifier or '(' before numeric constant
int B0 = 0, B1 = 0;
^
這是由于定義沖突導(dǎo)致的一個error,和NDK
版本有關(guān),在使用r15c和r9b低版本的時候都沒有遇到這個問題;
解決方法: 修改libavcodec/aaccoder.c 文件 B0改成b0(ps:就是把int型變量名改一下,避免沖突,名字隨便起)。
3)
libavcodec/hevc_mvs.c: In function 'derive_spatial_merge_candidates':
libavcodec/hevc_mvs.c:208:15: error: 'y0000000' undeclared (first use in this function)
((y ## v) >> s->ps.sps->log2_min_pu_size))
^
解決方法:將libavcodec/hevc_mvs.c文件的變量B0改成b0,xB0改成xb0,yB0改成yb0。
4)
libavcodec/opus_pvq.c: In function 'quant_band_template':
libavcodec/opus_pvq.c:498:9: error: expected identifier or '(' before numeric constant
int B0 = blocks;
^
解決方法:將libavcodec/opus_pvq.c文件的變量B0改成b0。
結(jié)語
? ? ? ? 除了上面的問題外,中間也遇到過configure.sh腳本沒執(zhí)行成功的問題,原因大都是空格鍵或一些老的參數(shù)過時了等問題。比如 -ffserver這個參數(shù)已經(jīng)不用了。
? ? ? ? 上面提到說推薦NDK版本是r17c以下的,是因為我們的build_android.sh,編譯腳本用用的編譯工具是gcc,但是NDK r17c以后的版本把gcc給移除了。所以如果現(xiàn)在用最新的版本r21的話會出現(xiàn)關(guān)于gcc的error??紤]更換編譯工具不用gcc應(yīng)該就能解決問題,但是不知道又會不會出現(xiàn)其它的問題…還需后續(xù)研究。