编译ffmpeg安卓库(clang篇),含armeabi-v7a , arm64-v8a, x86, x86_64
? ? 安卓新的NDK編譯工具替換成了clang,所以之前的編譯腳本需要做相應調整,本文總結了編譯過程中遇到的諸多問題,如果編譯過程中遇到問題,或編出的庫不符合需求,可參考后面的問題總結,希望能幫到你
環境
? ? 編譯環境:win10 +?msys2??
? ? DNK版本:android-ndk-21.2.6472646/?android-ndk-21.0.6113669/android-ndk-r20
? ?ffmpeg版本:?ffmpeg3.3.9/ffmpeg4.3.1
使用本文的編譯腳本,測試了linux和window10,android-ndk-21.2.6472646/?android-ndk-21.0.6113669/android-ndk-r20,編譯了?ffmpeg3.3.9/ffmpeg4.3.1,都能成功編譯
環境搭建
? ? 網上許多安裝類unix運行環境都需要翻墻,要么安裝速度很慢,本文使用國內源不需要翻墻,如果你安裝了其他的類unix運行環境(如cywin,?MinGW),理論上應該是可以直接進入后面的編譯步驟的,不過我沒嘗試過
1、msys2安裝?
? ? ? ? ?在清華大學鏡像網站下載并安裝?msys2?最新版本?,此外還有中科大,北京理工大學, 上海交大等鏡像源,64位系統建議下載x86_64版本,安裝一路點擊下一步就行
2、msys2配置
? ? ? ? 將默認源地址替換為清華大學鏡像地址,類似于Ubuntu設置鏡像源,這樣安裝其他工具速度會快很多,配置步驟如下
? ? ? ? 見清華大學鏡像網站msys2幫助文檔,我下載的最新版本默認有許多國內鏡像源在配置文件中,其他鏡像源的沒有試過,建議把國內的源放前面,我的配置順序如下
#清華大學 Server = https://mirrors.tuna.tsinghua.edu.cn/msys2/mingw/i686/ #中科大 Server = http://mirrors.ustc.edu.cn/msys2/mingw/i686/ #北京理工大學 Server = http://mirror.bit.edu.cn/msys2/mingw/i686/ Server = https://mirror.selfnet.de/msys2/mingw/i686/ #上海交大 Server = https://mirrors.sjtug.sjtu.edu.cn/msys2/mingw/i686/ Server = https://mirror.yandex.ru/mirrors/msys2/mingw/i686/ Server = https://sourceforge.net/projects/msys2/files/REPOS/MINGW/i686/ Server = https://www2.futureware.at/~nickoe/msys2-mirror/mingw/i686/配置完打開安裝路徑下msys2.exe(或按win鍵在程序列表中打開),執行?pacman -Sy?刷新軟件包數據即可。
? ? ? ?然后執行安裝路徑下msys2_shell.cmd打開msys終端,執行"pacman -Syuu"命令,中途可能會提示關閉終端,此時關閉msys,重新? ? ? ? ?打? ?開,再次執行"pacman -Syuu"命令,更新軟件包
? ? 這里順便附一個pacman包管理工具命令開始編譯
3、安裝make
? ? 在msys2終端執行pacman -S make,安裝make工具
pacman -S make編譯ffmpeg
? ? msys2安裝目錄下打開mingw64.exe,?切換到ffmpeg源碼路徑,windows?D:盤被掛載為/d/,以此類推,可用?df -h命令確認,不過盤符占用比較多時相應可能比較慢
? ? 新建一個buid.sh,將以下內容粘貼到文本,根據需求替換前三個變量,如果使用windows文本編輯器,切記保存為unix格式,否則可能會由于結束符不一致問題,報有語法錯誤,腳本加了一些輔助調試信息,和交互選項,所以比較長,將腳本保存到ffmpeg源碼路徑下,執行./build 5 ,可編譯armeabi-v7a , arm64-v8a, x86, x86_64?所有動態和靜態庫,如果只編譯某個版本的庫執行./build可以看到編譯選擇,選擇相應版本編號即可,輸出路徑下build.log可跟蹤編譯情況
#!/bin/bash#ffmpeg 版本 FFMPEG_VERSION=4.3.1 #NDK 路徑, 根據情況替換 export NDK=/d/Green_Sorft/Android/Sdk/ndk/21.2.6472646 #編譯輸出路徑 根據需求替換替換,默認在腳本上級目錄ffmpeg_for_android目錄下 OUT_DIR="`dirname $PWD`/ffmpeg_for_android/ffmpeg_${FFMPEG_VERSION}_lib" #編譯工具路徑,linux版本需根據情況替換 TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/windows-x86_64export TMPDIR=$OUT_DIR/tmp mkdir -p $TMPDIR #將ndk下yasm所在路徑添加到PATH環境變量 PATH=$PATH:$TOOLCHAIN/bin #創建/清空編譯日志 > $OUT_DIR/build.logfunction build_start() {echo "build FFmpeg for $ABI"./configure \--prefix=$OUT_DIR/$ABI \--disable-gpl \--enable-shared \--enable-static \--disable-doc \--disable-programs \--disable-avdevice \--disable-doc \--disable-symver \--cross-prefix=$CROSS_PREFIX \--target-os=android \--enable-cross-compile \--arch=$ARCH \--cpu=$CPU \--cc=$CC \--cxx=$CXX \--sysroot=$TOOLCHAIN/sysroot \--extra-cflags="-Os -fPIC $OPTIMIZE_CFLAGS" \configRet=$?echo "* config for $ABI ret:$configRet" >> $OUT_DIR/build.logif [ $configRet -eq 0 ]; thenecho "start make $ABI"make cleanmake -j64makeRet=$?echo "* make for $ABI return:$makeRet" >> $OUT_DIR/build.logif [ $makeRet -eq 0 ]; thenmake installmv_libsfielseecho "The config of FFmpeg for $ABI is failded"echo "* config for $ABI failed !!" >> $OUT_DIR/build.logfiecho "The Compilation of FFmpeg for $ABI is completed"echo "*************************" >> $OUT_DIR/build.log }function mv_libs() {mkdir -p $OUT_DIR/shared-libs/$ABImv $OUT_DIR/$ABI/lib/*.so $OUT_DIR/shared-libs/$ABImkdir -p $OUT_DIR/static-libs/$ABImv $OUT_DIR/$ABI/lib/*.a $OUT_DIR/static-libs/$ABIcp -rf $OUT_DIR/$ABI/include $OUT_DIR/cp -rf $OUT_DIR/$ABI/share/ffmpeg/examples $OUT_DIR/rm -rf $OUT_DIR/$ABI/ }#armv8-a aarch64 function build_arm64() {API=21ABI=arm64-v8aARCH=arm64CPU=armv8-aCC=$TOOLCHAIN/bin/aarch64-linux-android$API-clangCXX=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++CROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android-OPTIMIZE_CFLAGS="-march=$CPU"echo "* buidl for $ABI start !!" >> $OUT_DIR/build.logbuild_startecho "* buidl for $ABI end !!" >> $OUT_DIR/build.logecho "*************************" >> $OUT_DIR/build.log }#armv7-a function build_arm() {API=16ABI=armeabi-v7aARCH=armCPU=armv7-aCC=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clangCXX=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang++CROSS_PREFIX=$TOOLCHAIN/bin/arm-linux-androideabi-OPTIMIZE_CFLAGS="-march=$CPU -mfloat-abi=softfp -mfpu=vfp -marm"echo "* buidl for $ABI start !!" >> $OUT_DIR/build.logbuild_startecho "* buidl for $ABI end !!" >> $OUT_DIR/build.logecho "*************************" >> $OUT_DIR/build.log }#x86 i686 function build_x86() {API=16ABI=x86ARCH=x86CPU=x86CC=$TOOLCHAIN/bin/i686-linux-android$API-clangCXX=$TOOLCHAIN/bin/i686-linux-android$API-clang++CROSS_PREFIX=$TOOLCHAIN/bin/i686-linux-android-OPTIMIZE_CFLAGS="-march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32 -mno-stackrealign"echo "* buidl for $ABI start !!" >> $OUT_DIR/build.logbuild_startecho "* buidl for $ABI end !!" >> $OUT_DIR/build.logecho "*************************">> $OUT_DIR/build.logecho "">> $OUT_DIR/build.log }#x86_64 function build_x86_64() {API=21ABI=x86_64ARCH=x86_64CPU=x86-64CC=$TOOLCHAIN/bin/x86_64-linux-android$API-clangCXX=$TOOLCHAIN/bin/x86_64-linux-android$API-clang++CROSS_PREFIX=$TOOLCHAIN/bin/x86_64-linux-android-OPTIMIZE_CFLAGS="-march=$CPU -msse4.2 -mpopcnt -m64 -mtune=intel"echo "* buidl for $ABI start !!" >> $OUT_DIR/build.logbuild_startecho "* buidl for $ABI end !!" >> $OUT_DIR/build.logecho "*************************">> $OUT_DIR/build.log }function read_opt() {echo ""echo "please select onece"echo " 1、build for ABI=armeabi-v7a CPU=armv7-a"echo " 2、build for ABI=arm64-v8a CPU=armv8-a"echo " 3、build for ABI=x86 CPU=x86"echo " 4、build for ABI=x86_64 CPU=x86_64"echo " 5、build all"echo ""echo "input:"read option }option=$1 if [ "$option" = "" ];thenread_opt fiif [ "$option" = "1" ];thenecho "start build ABI=arm64-v8a CPU=armv8-a"build_arm64 elif [ "$option" = "2" ];thenecho "start build ABI=armeabi-v7a CPU=armv7-a"build_arm elif [ "$option" = "3" ];thenecho "start build ABI=x86 CPU=x86"build_x86 elif [ "$option" = "4" ];thenecho "start build ABI=x86_64 CPU=x86_64"build_x86_64 elif [ "$option" = "5" ];thenecho "start build all"build_arm64build_armbuild_x86build_x86_64 elseecho "invalid input" firm -rf $TMPDIR問題總結
1、編譯x86cpu時內聯匯編報錯
In file included from libswscale/x86/rgb2rgb.c:102:
 libswscale/x86/rgb2rgb_template.c:1666:13: error: inline assembly requires more registers than available
 ? ? ? ? ? ? "mov ? ? ? ? ? ? ? ? ? ? ? ?%4, %%"FF_REG_a"\n\t"
 ? ? ? ? ? ? ^
提供了一下4個解決方案
1、禁用asm,在ffmpeg?configure選項中添加--disable-asm禁用匯編,不過可能會影響運行效率
2、在修改ffmpeg路徑下config.h,將HAVE_EBP_AVAILABLE 設置為0?#define HAVE_EBP_AVAILABLE 0
3、這是ndk低版本編譯鏈中才存在的問題,可用24及以上版本編譯鏈,及將腳本中x86_build中的API設置為24及以上(可能會影響兼容性)
4、(推薦)在configure --extra-cflags選項中添加?-mno-stackrealign編譯選項
2、使用ffmpeg動態庫,編譯時提示找不到動態庫
在app下build.gradle 文件android內添加如下代碼
sourceSets.main{jniLibs.srcDirs=['libs'] }3、使用模擬器調試時,提示java.lang.UnsatisfiedLinkError: dlopen failed: "xxx.so" has text relocations(https://android.googlesource.com/platform/bionic/+/master/android-changes-for-ndk-developers.md#Text-Relocations-Enforced-for-API-level-23)
模擬器基本都是x86cpu,網上說只有6.0以上才有這個問題,網上的方案都是把aap下build.gradle中的targetSdkVersion設置為23以下,但是我用模擬器調試時似乎不能這么操作,修改后編不出APK,我不是搞安卓framework的,應用相關的不是很清楚,所以我直接使用靜態庫了,或者使用手機
4,提示找不到ysam或版本過低
首先在msys終端輸入yasm,看是否有這個命令,如果提示找不到命令,則在腳本中將ndk中android-ndk-r20\toolchains\llvm\prebuilt\windows-x86_64\bin\yasm添加到PATH環境變量中,PATH=$PATH:$TOOLCHAIN/bin ,如果有yasm,則用whereis?yasm命令,找到電腦中的yasm,將其重命名(記得改回去)或直接刪除,然后將ndk的yasm添加到path環境變量
5、在編譯armv7-a時,匯編文件報錯
libswscale/arm/rgb2yuv_neon_common.S:251:11: error: unexpected token in argument list
 CO_BV .dn d2.s16[2]
 ? ? ? ? ? ^
 <instantiation>:4:5: error: invalid instruction
 ? ? vmul y16x16_l, n16x16_l, CO_RY
 ? ? ^
 我在編譯ffmpeg4.3.1時沒有這個問題,但是編譯ffmpeg3.3.9時報錯,簡單粗暴的操作就是在ffmpeg?configure選項中添加--disable-asm禁用匯編,但是我們要斯文一點,可以選擇只禁用neon,即在armv7-a的ffmpeg?configure選項中加入--disable-neon
6、將ffmpeg所有的庫編譯為一個libffmpeg.so庫
目前只編譯出靜態庫,動態庫編譯編譯過程遇到了些問題,后面嘗試解決
https://blog.csdn.net/mvp_Dawn/article/details/109136921
總結
以上是生活随笔為你收集整理的编译ffmpeg安卓库(clang篇),含armeabi-v7a , arm64-v8a, x86, x86_64的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 学成在线--8.Freemarker入门
- 下一篇: C#正则表达式用法总结
