背景:需要做一個(gè)Android端的視頻轉(zhuǎn)碼so庫(kù)使用炉菲,需要用到FFmpeg開源庫(kù)堕战,并且按需求集成進(jìn)X264和vo-aacenc兩個(gè)靜態(tài)庫(kù),隨后就走上了不斷的踩坑和爬坑之路拍霜,現(xiàn)在特地記錄一下嘱丢,以供將來(lái)腦子不好的時(shí)候有個(gè)回想的根據(jù)。
構(gòu)建環(huán)境
系統(tǒng):Ubuntu16.04_64位(是的祠饺,還是Mac上跑的虛擬機(jī)越驻,網(wǎng)上有太多的Mac構(gòu)建FFmpeg的過(guò)程,然后爬了個(gè)把星期都不能用道偷,有哪位大神有靠譜點(diǎn)的教程歡迎分享)缀旁;
NDK:android-ndk-r9d(不要問(wèn)我為什么不用最新的,都是淚T T);
FFmpeg:2.0.7版本勺鸦,根據(jù)官方的Release Note發(fā)現(xiàn)3.0以上版本已經(jīng)不再支持vo-aacenc了并巍,所以下了2.0.X的版本;
vo-aacenc:0.1.3版本换途,是的懊渡,最新版本還是2013-07-27發(fā)布的嘶窄,就是說(shuō)該庫(kù)已經(jīng)光榮退休了,有條件的推薦使用fdk-aac嘗試編譯一下距贷;
X264:最新的就好,沒(méi)啥要求吻谋。
過(guò)程
過(guò)程無(wú)非就是寫編譯腳步忠蝗,調(diào)編譯腳本的過(guò)程,剛學(xué)習(xí)寫這玩意漓拾,過(guò)程時(shí)異常曲折阁最。首先從各自網(wǎng)站上下載FFmpeg、X264和vo-aacenc骇两,然后把壓縮包解壓后放到同一個(gè)目錄下速种,不如說(shuō)將x264以及vo-aacenc都放在FFmpeg解壓出來(lái)的文件夾下。這樣的好處是少寫幾個(gè)代碼低千,整個(gè)編譯過(guò)程可以放在同一個(gè)腳本中運(yùn)行配阵。順序是按照x264\vo-aacenc\ffmpeg的先后編譯,因?yàn)镕Fmpeg編譯的時(shí)候需要用到前面兩個(gè)已經(jīng)生成好的靜態(tài)庫(kù)示血。主要的腳本編譯放到后面去說(shuō)棋傍。
坑
期間真的遇到了無(wú)數(shù)的坑,差點(diǎn)都要放棄了难审,(╯°Д°)╯︵ ┻━┻
主要摘了一些典型的記錄一下:
1.腳本運(yùn)行中出現(xiàn)No such file or directory VS no such command
別笑瘫拣,還真是這種問(wèn)題折磨的死去活來(lái)死去,因?yàn)槟_本里面要配置的東西太多了告喊,ToolChains的路徑又要配置好幾次麸拄,稍不留神寫錯(cuò)一個(gè)路徑,編譯就無(wú)法成功黔姜,這個(gè)時(shí)候千萬(wàn)淡定拢切,看看腳本命令行之間是不是都用\分隔著,路徑有沒(méi)有出錯(cuò)地淀,最好打印一下失球,echo $PATH
之類的。
2.In file included from libavcodec/x86/mpegvideoenc.c:81:0: libavcodec/x86/mpegvideoenc_template.c: In function 'dct_quantize_SSSE3': libavcodec/x86/mpegvideoenc_template.c:144:9: error: 'asm' operand has impossible constraints __asm__ volatile( libavcodec/x86/mpegvideoenc_template.c:179:9: error: 'asm' operand has impossible constraints __asm__ volatile( CC libavcodec/x86/videodsp_init.o CC libpostproc/postprocess.o common.mak:48: recipe for target 'libavcodec/x86/mpegvideoenc.o' failed make: *** [libavcodec/x86/mpegvideoenc.o] Error 1 make: *** Waiting for unfinished jobs....
典型錯(cuò)誤帮毁,去掉腳本中的--enable-asm
3.undefined reference to "__umodsi3"
undefined reference to "__udivdi3"
在腳本中沒(méi)有指定連接的GCC庫(kù)实苞,添加-lgcc,多說(shuō)一句烈疚,-lgcc代表鏈接器將連接GCC的支持庫(kù)libgcc.a黔牵,-lm代表鏈接器將連接GCC的標(biāo)準(zhǔn)數(shù)學(xué)庫(kù)libm.a,-lc代表鏈接器將連接GCC的標(biāo)準(zhǔn)C庫(kù)libc.a爷肝。
4.諸如C compiler not found
之類的錯(cuò)誤就是你的GCC路徑?jīng)]設(shè)對(duì)了猾浦。
構(gòu)建腳本
最后陆错,貼一下構(gòu)建的腳本(這個(gè)雖然是現(xiàn)成的,但是思想和踩坑經(jīng)過(guò)才是最重要的金赦!)
再啰嗦一句音瓷,標(biāo)題上寫的是構(gòu)建基于X86和armeabi的,那么為什么不加上arm64呢夹抗?對(duì)于ARM64架構(gòu)的so庫(kù)绳慎,目前無(wú)法編譯,因?yàn)閍rm64的GCC版本于Android-21(5.0.1-2014年發(fā)布)才開始支持漠烧,而FFmpeg中的AAC編解碼的開源模塊于2013年就已停止維護(hù)杏愤,官方文檔也說(shuō)明該庫(kù)不支持ARM64的架構(gòu)。話又說(shuō)回來(lái)已脓,64位也是兼容32位的靜態(tài)庫(kù)的珊楼,只不過(guò)性能上就要犧牲一下了。MIPS的畢竟太少太少度液,就不折騰了厕宗。
貼一下X86的運(yùn)行腳本,armeabi的稍微換一下就好了
#!/bin/bash
function setup_paths
{
export PLATFORM=$NDKROOT/platforms/$PLATFORM_VERSION/arch-$ARCH
if [ ! -d $PLATFORM ]; then
echo $PLATFORM does not exist
exit 1
fi
echo "Using platform: $PLATFORM"
export PATH=${PATH}:$PREBUILT/bin/
export CROSS_COMPILE=$PREBUILT/bin/$EABIARCH-
export CFLAGS=$OPTIMIZE_CFLAGS
export CPPFLAGS="$CFLAGS"
export CFLAGS="$CFLAGS"
export CXXFLAGS="$CFLAGS"
export CXX="${CROSS_COMPILE}g++ --sysroot=$PLATFORM -m32"
export AS="${CROSS_COMPILE}gcc --sysroot=$PLATFORM"
export CC="${CROSS_COMPILE}gcc --sysroot=$PLATFORM -m32"
export PKG_CONFIG="${CROSS_COMPILE}pkg-config"
export LD="${CROSS_COMPILE}ld"
export NM="${CROSS_COMPILE}nm"
export STRIP="${CROSS_COMPILE}strip"
export RANLIB="${CROSS_COMPILE}ranlib"
export AR="${CROSS_COMPILE}ar"
export LDFLAGS="-Wl,-rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib -nostdlib -lm -lc -lgcc -ldl -llog"
export PKG_CONFIG_LIBDIR=$PREFIX/lib/pkgconfig/
export PKG_CONFIG_PATH=$PREFIX/lib/pkgconfig/
if [ ! -f "${CROSS_COMPILE}gcc" ]; then
echo "Gcc does not exists in path: ${CROSS_COMPILE}gcc"
exit 1;
fi
if [ ! -f "${PKG_CONFIG}" ]; then
echo "Pkg config does not exists in path: ${PKG_CONFIG} - Probably BUG in NDK but..."
set +e
SYS_PKG_CONFIG=$(which pkg-config)
if [ "$?" -ne 0 ]; then
echo "This system does not contain system pkg-config, so we can do anything"
exit 1
fi
set -e
cat > $PKG_CONFIG << EOF
#!/bin/bash
pkg-config \$*
EOF
chmod u+x $PKG_CONFIG
echo "Because we have local pkg-config we will create it in ${PKG_CONFIG} directory using ${SYS_PKG_CONFIG}"
fi
}
function build_x264_x86
{
echo "Starting build x264 for $ARCH"
cd x264
./configure \
--prefix=$PREFIX \
--host=$ARCH-linux \
--enable-static \
$ADDITIONAL_CONFIGURE_FLAG
make clean
make -j4 install
make clean
cd ..
echo "finished x264 for $ARCH"
}
function build_aac_x86
{
echo "Starting build aac for $ARCH"
cd vo-aacenc-0.1.3
./configure \
--prefix=$PREFIX \
--host=$ARCH-linux \
--disable-dependency-tracking \
--disable-shared \
--enable-static \
--with-pic \
$ADDITIONAL_CONFIGURE_FLAG
make clean
make -j4 install
make clean
cd ..
echo "Finished aac for $ARCH"
}
function build_ffmpeg_x86
{
echo "Starting build ffmpeg-x86 for $ARCH"
./configure --target-os=linux \
--prefix="$PREFIX" \
--enable-cross-compile \
--enable-runtime-cpudetect \
--arch=$ARCH \
--cc=$PREBUILT/bin/$EABIARCH-gcc \
--cross-prefix=$PREBUILT/bin/$EABIARCH- \
--disable-stripping \
--nm=$PREBUILT/bin/$EABIARCH-nm \
--sysroot=$PLATFORM \
--extra-cflags=" -O3 -fpic -DANDROID -DHAVE_SYS_UIO_H=1 -Dipv6mr_interface=ipv6mr_ifindex -fasm -Wno-psabi -fno-short-enums -fno-strict-aliasing -finline-limit=300 $OPTIMIZE_CFLAGS " \
--extra-ldflags="-Wl,-rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib -nostdlib -lc -lm -ldl -llog -L$PREFIX/lib" \
--extra-cflags="-I$PREFIX/include" \
--extra-libs="-lgcc" \
--enable-static \
--disable-shared \
--disable-yasm \
--disable-amd3dnow \
--enable-version3 \
--enable-gpl \
--enable-libvo-aacenc \
--enable-libx264 \
--disable-everything \
--enable-parser=h263 \
--enable-parser=mpeg4video \
--enable-demuxer=mov \
--enable-decoder=amrnb \
--enable-decoder=amrwb \
--enable-decoder=h263 \
--enable-decoder=aac \
--enable-decoder=h264 \
--enable-decoder=mpeg4 \
--enable-encoder=mjpeg \
--enable-encoder=libvo_aacenc \
--enable-encoder=libx264 \
--enable-muxer=mp4 \
--enable-muxer=mov \
--enable-protocol=file \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-network \
--disable-swscale-alpha \
--disable-debug \
--disable-logging \
--enable-small \
$ADDITIONAL_CONFIGURE_FLAG
make clean
make -j4 install
make clean
echo "Finished ffmpeg_x86 for $ARCH"
}
NDKROOT=/home/young/Documents/android-ndk-r9d
EABIARCH=i686-linux-android
ARCH=x86
OPTIMIZE_CFLAGS="-m32 -march=i686"
PREBUILT=$NDKROOT/toolchains/$ARCH-4.8/prebuilt/linux-x86_64
PREFIX=/home/young/Documents/FFmpeg3.1.2/output_android
PLATFORM_VERSION=android-14
ADDITIONAL_CONFIGURE_FLAG=--disable-asm
setup_paths
build_x264_x86
build_aac_x86
build_ffmpeg_x86
腳本中用的都是絕對(duì)路徑恨诱,現(xiàn)實(shí)中使用的話需要都改成當(dāng)前電腦上的配置路徑媳瞪。PREFIX是靜態(tài)庫(kù)的輸出文件夾,setup_paths方法用于配置腳本的各種設(shè)置,后面的幾個(gè)方法就是依次構(gòu)建的過(guò)程照宝。具體的配置命令的意思可以通過(guò)在本地包含configure的目錄下使用./configure --help
的命令查詢蛇受。
總結(jié)一點(diǎn)就是膽大心細(xì),多Google厕鹃!