Linux下構(gòu)建帶vo-aacenc和x264的FFmpeg的Android ARM以及X86版本庫(kù)

背景:需要做一個(gè)Android端的視頻轉(zhuǎn)碼so庫(kù)使用,需要用到FFmpeg開(kāi)源庫(kù),并且按需求集成進(jìn)X264vo-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ú)非就是寫(xiě)編譯腳步,調(diào)編譯腳本的過(guò)程,剛學(xué)習(xí)寫(xiě)這玩意,過(guò)程時(shí)異常曲折。首先從各自網(wǎng)站上下載FFmpeg、X264和vo-aacenc,然后把壓縮包解壓后放到同一個(gè)目錄下,不如說(shuō)將x264以及vo-aacenc都放在FFmpeg解壓出來(lái)的文件夾下。這樣的好處是少寫(xiě)幾個(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的路徑又要配置好幾次,稍不留神寫(xiě)錯(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)題上寫(xiě)的是構(gòu)建基于X86和armeabi的,那么為什么不加上arm64呢?對(duì)于ARM64架構(gòu)的so庫(kù),目前無(wú)法編譯,因?yàn)閍rm64的GCC版本于Android-21(5.0.1-2014年發(fā)布)才開(kāi)始支持,而FFmpeg中的AAC編解碼的開(kāi)源模塊于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!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容