使用Android NDK編譯ffmpeg

系統(tǒng):macOS High Sierra 10.13.4
NDK:android-ndk-r11c
FFmpeg:ffmpeg-3.3.7

最近基于ffmpeg用c++寫(xiě)了一個(gè)流媒體播放器,支持播放本地/網(wǎng)絡(luò)文件、rtmp/rtsp流,想將其移植到Android中,第一步要做的工作就是編譯Android能用的ffmpeg,之前編譯ffmpeg都是使用NDK直接編譯,問(wèn)題不大,而Android的NDK更新模式就如同Android的Framework更新一樣,即新版系統(tǒng)中會(huì)不斷調(diào)整(優(yōu)化)文件位置,所以做過(guò)Android系統(tǒng)開(kāi)發(fā)的朋友們應(yīng)該時(shí)常遇到“No such file or directory”。廢話不多說(shuō),開(kāi)始。

1、為何不使用網(wǎng)友直接編譯好的庫(kù)?NO,因?yàn)槲疫@個(gè)播放器是跨平臺(tái)的,而ffmpeg中的AVMediaType與IOS中AVFoundation下的AVMediaType沖突了,為了兼容IOS,所以我將ffmpeg源碼中的AVMediaType全局替換成了FFMAVMediaType然后再進(jìn)行編譯。

sed -i '' "s/AVMediaType/FFMAVMediaType/g" `grep -rl AVMediaType ./ffmpeg-*`
/*如果報(bào)錯(cuò):sed: RE error: illegal byte sequence
  缺少環(huán)境變量,在shell輸入:
  export LC_COLLATE='C'
  export LC_CTYPE='C'*/

2、準(zhǔn)備N(xiāo)DK和FFmpeg源碼,也可以使用Android Studio的SDK Manager一鍵下載NDK,更加方便。

NDK下載地址:https://developer.android.google.cn/ndk/downloads/
FFmpeg下載地址:http://www.ffmpeg.org/download.html

3、下載完成后進(jìn)入到ffmpeg根目錄創(chuàng)建腳本build-android.sh
3.1 腳本一:一次性編譯所有平臺(tái)

#NDK位置
export NDK=/Users/luohan/Library/Android/my_ndk_bundle/android-ndk-r11c

#編譯成功后的產(chǎn)出位置
PREFIX=android
NDK_HOST_PLATFORM=darwin-x86_64

#編譯過(guò)程中的臨時(shí)文件存放
export TMPDIR=/Users/luohan/ffmpegTemp

#各平臺(tái)交叉編譯鏈位置
ARM_LINUX_TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
ARM_LINUX_SYSROOT=$NDK/platforms/android-21/arch-arm

ARM_64_TOOLCHAIN=$NDK/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64
ARM_64_SYSROOT=$NDK/platforms/android-21/arch-arm64

X86_TOOLCHAIN=$NDK/toolchains/x86-4.9/prebuilt/darwin-x86_64
X86_SYSROOT=$NDK/platforms/android-21/arch-x86

X86_64_TOOLCHAIN=$NDK/toolchains/x86_64-4.9/prebuilt/darwin-x86_64
X86_64_SYSROOT=$NDK/platforms/android-21/arch-x86_64

COMMON_OPTIONS="\
    --prefix=$PREFIX/ \
    --target-os=android \
    --disable-static \
    --enable-shared \
    --enable-small \
    --disable-programs \
    --disable-ffmpeg \
    --disable-ffplay \
    --disable-ffprobe \
    --disable-doc \
    --disable-symver \
    --disable-asm \
    --enable-cross-compile \
    "

function build_android {
    ./configure \
    --libdir=${PREFIX}/libs/armeabi-v7a \
    --incdir=${PREFIX}/includes/armeabi-v7a \
    --pkgconfigdir=${PREFIX}/pkgconfig/armeabi-v7a \
    --arch=arm \
    --cpu=armv7-a \
    --cross-prefix="${ARM_LINUX_TOOLCHAIN}/bin/arm-linux-androideabi-" \
    --sysroot="${ARM_LINUX_SYSROOT}/" \
    --extra-cflags="-march=armv7-a -mfloat-abi=softfp -mfpu=neon -I $ARM_LINUX_SYSROOT/usr/include/" \
    --extra-ldexeflags=-pie \
    ${COMMON_OPTIONS}
    make clean
    make -j8 && make install

    ./configure \
    --libdir=${PREFIX}/libs/arm64-v8a \
    --incdir=${PREFIX}/includes/arm64-v8a \
    --pkgconfigdir=${PREFIX}/pkgconfig/arm64-v8a \
    --arch=aarch64 \
    --cpu=armv8-a \
    --cross-prefix="${ARM_64_TOOLCHAIN}/bin/aarch64-linux-android-" \
    --sysroot="${ARM_64_SYSROOT}/" \
    --extra-libs=-lgcc \
    --extra-cflags="$ARM_64_SYSROOT/usr/include/" \
    --extra-ldexeflags=-pie \
    ${COMMON_OPTIONS} 
    make clean
    make -j8 && make install

    ./configure \
    --libdir=${PREFIX}/libs/x86 \
    --incdir=${PREFIX}/includes/x86 \
    --pkgconfigdir=${PREFIX}/pkgconfig/x86 \
    --arch=x86 \
    --cpu=i686 \
    --cross-prefix="${X86_TOOLCHAIN}/bin/i686-linux-android-" \
    --sysroot="${X86_SYSROOT}/" \
    --extra-cflags="$X86_SYSROOT/usr/include/" \
    --extra-ldexeflags=-pie \
    ${COMMON_OPTIONS} 
    make clean
    make -j8 && make install

    ./configure \
    --libdir=${PREFIX}/libs/x86_64 \
    --incdir=${PREFIX}/includes/x86_64 \
    --pkgconfigdir=${PREFIX}/pkgconfig/x86_64 \
    --arch=x86_64 \
    --cpu=x86_64 \
    --cross-prefix="${X86_64_TOOLCHAIN}/bin/x86_64-linux-android-" \
    --sysroot="${X86_64_SYSROOT}/" \
    --extra-cflags="$X86_64_SYSROOT/usr/include/" \
    --extra-ldexeflags=-pie \
    ${COMMON_OPTIONS}
    make clean
    make -j8 && make install
};

build_android

3.1 腳本二:只針對(duì)一種平臺(tái)進(jìn)行編譯

#!/bin/sh
export NDK=/Users/luohan/Library/Android/my_ndk_bundle/android-ndk-r11c
SYSROOT=$NDK/platforms/android-21/arch-arm
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
PREFIX=android
ADDI_CFLAGS="-marm"

function build_one
{
./configure \
--prefix="${PREFIX}/" \
--enable-shared \
--disable-static \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-avdevice \
--disable-doc \
--disable-symver \
--disable-asm \
--cross-prefix="${TOOLCHAIN}/bin/arm-linux-androideabi-" \
--target-os=android \
--arch=arm \
--enable-cross-compile \
--sysroot="${SYSROOT}/" \
--extra-cflags="-mfpu=neon -mfloat-abi=softfp -I $NDK/platforms/android-21/arch-arm/usr/include/" \
--extra-ldflags="$ADDI_LDFLAGS" 

$ADDITIONAL_CONFIGURE_FLAG
make clean
make
make install
}

build_one
Android版ffmpeg編譯完成,此腳本支持Android的4個(gè)平臺(tái)的編譯

說(shuō)明下為什么這里我要使用舊版的NDK,因?yàn)槲覀冊(cè)趯?duì)ffmpeg進(jìn)行交叉編譯時(shí)需要引用到c庫(kù)(--extra-cflags),此前,舊版NDK的c庫(kù)目錄位置在“NDK/platforms/android-21/arch-arm64/usr/include/”中,而新版NDK中所以Android版本下的usr文件夾中都移除了include文件夾,全局搜索了一下發(fā)現(xiàn),它們被集合放在另一個(gè)目錄“NDK/sysroot/usr/include/”,這算是一個(gè)優(yōu)化吧,但是引入該目錄后,編譯仍然報(bào)找不到c文件,具體原因不明,最后我直接使用舊版NDK進(jìn)行編譯,平臺(tái)版本選擇android-21,因?yàn)閍ndroid-21中全平臺(tái)的c庫(kù)都有,再次編譯,成功。

舊NDK中c庫(kù)與新NDK中c庫(kù)的內(nèi)容對(duì)比,我猜想是多版本的集合體

編譯過(guò)程中還遇到過(guò)其他問(wèn)題,有時(shí)候命令行報(bào)錯(cuò)不清晰,不能說(shuō)明問(wèn)題,這時(shí)就需要打開(kāi)config.log查看詳細(xì)報(bào)錯(cuò),能幫助我們迅速對(duì)癥下藥,以下我粗略地羅列了幾個(gè)問(wèn)題的解決方案:

/toolchains/aarch64-linux-android-4.9/prebuilt//bin/aarch64-linux-android-gcc is unable to create an executable file.
C compiler test failed.
/*1.gcc交叉編譯文件位置不對(duì)(可通過(guò)查看config.log獲知)。
  2.沒(méi)有制定臨時(shí)編譯文件存放目錄,或目錄沒(méi)有提權(quán)。*/
WARNING: /Users/luohan/Library/Android/my_ndk_bundle/android-ndk-r16-beta1/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-pkg-config not found, library detection may fail.
/*警告,這種警告可直接無(wú)視*/
/bin/sh: ranlib/usr/local/lib/libavdevice.a: No such file or directory
make: *** [install-libavdevice-static] Error 127
/*未設(shè)置臨時(shí)文件位置所致*/
CC  libavcodec/aacdec.o
/var/folders/6c/zwgcjwzn7y3b5z8wzvd3b8h00000gn/T//ccjyLRuc.s: Assembler messages:
/var/folders/6c/zwgcjwzn7y3b5z8wzvd3b8h00000gn/T//ccjyLRuc.s:16330: Error: selected processor does not support ARM mode `ubfx r1,r2,#0,#4'
/var/folders/6c/zwgcjwzn7y3b5z8wzvd3b8h00000gn/T//ccjyLRuc.s:16331: Error: selected processor does not support ARM mode `ubfx r0,r2,#4,#4'
/var/folders/6c/zwgcjwzn7y3b5z8wzvd3b8h00000gn/T//ccjyLRuc.s:16491: Error: selected processor does not support ARM mode `ubfx r2,r1,#0,#2'
/var/folders/6c/zwgcjwzn7y3b5z8wzvd3b8h00000gn/T//ccjyLRuc.s:16492: Error: selected processor does not support ARM mode `ubfx r7,r1,#2,#2'
/var/folders/6c/zwgcjwzn7y3b5z8wzvd3b8h00000gn/T//ccjyLRuc.s:16494: Error: selected processor does not support ARM mode `ubfx r8,r1,#4,#2'
/var/folders/6c/zwgcjwzn7y3b5z8wzvd3b8h00000gn/T//ccjyLRuc.s:16496: Error: selected processor does not support ARM mode `ubfx r10,r1,#6,#2'
/var/folders/6c/zwgcjwzn7y3b5z8wzvd3b8h00000gn/T//ccjyLRuc.s:16501: Error: selected processor does not support ARM mode `rbit r1,r1'
/var/folders/6c/zwgcjwzn7y3b5z8wzvd3b8h00000gn/T//ccjyLRuc.s:16687: Error: selected processor does not support ARM mode `ubfx r2,r3,#0,#2'
/var/folders/6c/zwgcjwzn7y3b5z8wzvd3b8h00000gn/T//ccjyLRuc.s:16688: Error: selected processor does not support ARM mode `ubfx r1,r3,#2,#2'
/var/folders/6c/zwgcjwzn7y3b5z8wzvd3b8h00000gn/T//ccjyLRuc.s:16690: Error: selected processor does not support ARM mode `ubfx r0,r3,#4,#2'
/var/folders/6c/zwgcjwzn7y3b5z8wzvd3b8h00000gn/T//ccjyLRuc.s:16692: Error: selected processor does not support ARM mode `ubfx lr,r3,#6,#2'
/var/folders/6c/zwgcjwzn7y3b5z8wzvd3b8h00000gn/T//ccjyLRuc.s:16842: Error: selected processor does not support ARM mode `ubfx r2,r3,#0,#4'
/var/folders/6c/zwgcjwzn7y3b5z8wzvd3b8h00000gn/T//ccjyLRuc.s:16843: Error: selected processor does not support ARM mode `ubfx r1,r3,#4,#4'
make: *** [libavcodec/aacdec.o] Error 1
/*.configure中加入–-disable-asm*/
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容