最近也是準(zhǔn)備學(xué)習(xí)音視頻相關(guān)的內(nèi)容逮走,可在第一步--編譯就卡住了很久贯莺,遇到很多莫名其妙的坑,可謂編譯的血淚史怪与,但是在查閱幾十篇博客和逛爛StackOverFlow之后,終于算是成功的把ffmpeg給編譯出來(lái)了缅疟,現(xiàn)在分享給大家一些我踩過(guò)的坑分别。
編譯環(huán)境
本機(jī)系統(tǒng):macOS Big Sur 11.2.1
ffmpeg: 4.4
ndk:r21e
一、準(zhǔn)備工作
下載 FFmpeg
點(diǎn)擊這個(gè)
下載完成之后解壓即可存淫。
下載ndk(需要翻墻)耘斩,如果是Android開(kāi)發(fā)者可以直接自己的Sdk目錄下找到ndk(無(wú)需重新下載)。打開(kāi)Android Studio去這個(gè)目錄下面找
可以看到這個(gè)目錄下有個(gè)ndk的目錄
二桅咆、編寫(xiě)編譯腳本
1.先進(jìn)入解壓好的ffmpeg文件夾括授,找到configure文件
用記事本或者VSCode之類(lèi)的編輯器打開(kāi),找到以下代碼并進(jìn)行替換
# 注釋掉默認(rèn)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)'
# 替換為:
SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'
LIB_INSTALL_EXTRA_CMD='$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'
SLIB_INSTALL_LINKS='$(SLIBNAME)'
注意第二行的 LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'
$$(RANLIB)和"$(LIBDIR)/$(LIBNAME)"之間有一個(gè)空格岩饼,好像空格打掉了編譯會(huì)出問(wèn)題
改好之后記得保存
2.新建構(gòu)建腳本(重要)
在解壓出來(lái)的ffmpeg目錄下打開(kāi)命令行工具荚虚,輸入
touch build_android.sh
然后隨便找個(gè)編輯器打開(kāi)這個(gè)編譯文件,vim籍茧、Sublime版述、VSCode都行。
復(fù)制粘貼以下編譯代碼寞冯,對(duì)編譯代碼不熟悉的渴析,后面我會(huì)一步步的解析這個(gè)編譯腳本
#!/bin/bash
# 以下路徑需要修改成自己的NDK目錄
TOOLCHAIN=/xxxxxx/toolchains/llvm/prebuilt/darwin-x86_64
# 最低支持的android sdk版本
API=21
function build_android
{
echo "Compiling FFmpeg for $CPU"
./configure \
--prefix=$PREFIX \
--disable-neon \
--disable-hwaccels \
--disable-gpl \
--disable-postproc \
--enable-shared \
--enable-jni \
--disable-mediacodec \
--enable-small \
--enable-gpl \
--disable-decoder=h264_mediacodec \
--disable-static \
--disable-doc \
--disable-programs \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-avdevice \
--disable-symver \
--cross-prefix=$CROSS_PREFIX \
--target-os=android \
--arch=$ARCH \
--cpu=$CPU \
--cc=$CC \
--cxx=$CXX \
--enable-cross-compile \
--sysroot=$SYSROOT \
--extra-cflags="-mno-stackrealign -Os -fpic $OPTIMIZE_CFLAGS" \
--extra-ldflags="$ADDI_LDFLAGS" \
$ADDITIONAL_CONFIGURE_FLAG
make clean
make -j4
make install
echo "The Compilation of FFmpeg for $CPU is completed"
}
#armv8-a
ARCH=arm64
CPU=armv8-a
# r21版本的ndk中所有的編譯器都在/toolchains/llvm/prebuilt/darwin-x86_64/目錄下(clang)
CC=$TOOLCHAIN/bin/aarch64-linux-android$API-clang
CXX=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++
# NDK頭文件環(huán)境
SYSROOT=$TOOLCHAIN/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android-
# so輸出路徑
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-march=$CPU"
build_android
# 交叉編譯工具目錄,對(duì)應(yīng)關(guān)系如下
# armv8a -> arm64 -> aarch64-linux-android-
# armv7a -> arm -> arm-linux-androideabi-
# x86 -> x86 -> i686-linux-android-
# x86_64 -> x86_64 -> x86_64-linux-android-
# CPU架構(gòu)
#armv7-a
ARCH=arm
CPU=armv7-a
CC=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang
CXX=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang++
SYSROOT=$TOOLCHAIN/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/arm-linux-androideabi-
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=vfp -marm -march=$CPU "
build_android
#x86
ARCH=x86
CPU=x86
CC=$TOOLCHAIN/bin/i686-linux-android$API-clang
CXX=$TOOLCHAIN/bin/i686-linux-android$API-clang++
SYSROOT=$TOOLCHAIN/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/i686-linux-android-
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32"
build_android
#x86_64
ARCH=x86_64
CPU=x86-64
CC=$TOOLCHAIN/bin/x86_64-linux-android$API-clang
CXX=$TOOLCHAIN/bin/x86_64-linux-android$API-clang++
SYSROOT=$TOOLCHAIN/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/x86_64-linux-android-
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-march=$CPU -msse4.2 -mpopcnt -m64 -mtune=intel"
# 方法調(diào)用
build_android
選一個(gè)編譯單元來(lái)解析
#armv8-a
ARCH=arm64
CPU=armv8-a
# r21版本的ndk中所有的編譯器都在/toolchains/llvm/prebuilt/darwin-x86_64/目錄下(clang)
CC=$TOOLCHAIN/bin/aarch64-linux-android$API-clang
CXX=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++
# NDK頭文件環(huán)境
SYSROOT=$TOOLCHAIN/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android-
# so輸出路徑
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-march=$CPU"
build_android
ARCH、CPU简十、CC這些檬某,相當(dāng)于定義變量撬腾,后面可以通過(guò) $+變量名 進(jìn)行引用螟蝙。這個(gè)我相信大家有一點(diǎn)編程基礎(chǔ)的都不難理解。再變量定義過(guò)后最后一句build_android是執(zhí)行定義的方法民傻,也就是
function build_android
{
echo "Compiling FFmpeg for $CPU"
./configure \
--prefix=$PREFIX \
--disable-neon \
--disable-hwaccels \
--disable-gpl \
--disable-postproc \
--enable-shared \
--enable-jni \
--disable-mediacodec \
--enable-small \
--enable-gpl \
--disable-decoder=h264_mediacodec \
--disable-static \
--disable-doc \
--disable-programs \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-avdevice \
--disable-symver \
--cross-prefix=$CROSS_PREFIX \
--target-os=android \
--arch=$ARCH \
--cpu=$CPU \
--cc=$CC \
--cxx=$CXX \
--enable-cross-compile \
--sysroot=$SYSROOT \
--extra-cflags="-mno-stackrealign -Os -fpic $OPTIMIZE_CFLAGS" \
--extra-ldflags="$ADDI_LDFLAGS" \
$ADDITIONAL_CONFIGURE_FLAG
make clean
make -j4
make install
echo "The Compilation of FFmpeg for $CPU is completed"
}
這一段胰默。
需要注意的點(diǎn)是
編譯腳本最前面的TOOLCHAIN變量,路徑一定要寫(xiě)對(duì)漓踢,后面的變量如果有對(duì)TOOLCHAIN進(jìn)行拼接牵署,也一定要檢查該目錄下的文件路徑是否正確,以及拼接之后的文件是否存在喧半,因?yàn)椴煌姹緉dk可能里面的內(nèi)容或者位置不同奴迅,我不確定您看到這邊文章的時(shí)候里面的文件是否是和我當(dāng)前目錄下的文件一致。如果發(fā)現(xiàn)我給出的編譯腳本中的文件位置和您所使用的ndk文件位置有出入挺据,以自己ndk版本的文件位置為準(zhǔn)
接下來(lái)一起來(lái)解析一下build_android這個(gè)方法取具。
1.echo為打印輸出語(yǔ)句脖隶,沒(méi)什么可說(shuō)的,相當(dāng)于java中的print函數(shù)
2.make clean 每次編譯之前清空上次編譯的內(nèi)容
3.make -j4 使用4核編譯
4.make install 開(kāi)始編譯
重頭戲在這條參數(shù)鏈上暇检,也是我踩坑很久的地方
./configure 表示調(diào)用同級(jí)目錄的configure文件产阱,也就是我們最開(kāi)始修改了4行代碼的那個(gè)文件,后面的--xxxx-xxx 這些配置項(xiàng)具體的我就不細(xì)說(shuō)块仆,有興趣的可以直接用Sublime构蹬、VSCode等編譯器打開(kāi)configure文件,找到Help options 里面每個(gè)參數(shù)都有解釋?zhuān)@里我截取一小段悔据,雖然是英文庄敛,可能對(duì)英文不好的同學(xué)不太友好,但是這個(gè)年代不會(huì)還有人不會(huì)用翻譯軟件吧科汗,不會(huì)吧铐姚,不會(huì)吧?
坑1
你會(huì)看到網(wǎng)上的有些編譯腳本是這樣的
炸一看肛捍,好像沒(méi)有什么問(wèn)題隐绵,但是你開(kāi)始編譯,你就會(huì)發(fā)現(xiàn)你定義好的$PREFIX找不到文件或者目錄甚至--disable-neon: command not found拙毫。是電腦出問(wèn)題了依许?還是環(huán)境出問(wèn)題了?還是打開(kāi)的姿勢(shì)不對(duì)缀蹄?問(wèn)題的原因在于在整個(gè)參數(shù)配置鏈中不能有注釋及不該有的空格峭跳。我們看到的
# 指定輸出目錄
# 各種配置項(xiàng),想詳細(xì)了解的可以打開(kāi)configure文件找到Help options:查看
這類(lèi)的注釋都會(huì)影響編譯缺前。插入注釋?zhuān)诰幾g解析參數(shù)鏈的時(shí)候就會(huì)解析不到注釋后的那一項(xiàng)參數(shù)配置蛀醉,同理,亂加空格也會(huì)導(dǎo)致同樣的錯(cuò)誤衅码。所以拯刁,無(wú)論在用網(wǎng)上誰(shuí)的編譯腳本進(jìn)行編譯的時(shí)候,都應(yīng)該檢查參數(shù)鏈中是否有注釋或者是多余的空格逝段。
坑2
你可能會(huì)看到有些編譯腳本是這樣
炸是一看是不是還是沒(méi)有什么問(wèn)題垛玻?但是你會(huì)發(fā)現(xiàn)你$CXX路徑找不到,此時(shí)你會(huì)去一個(gè)目錄一個(gè)目錄對(duì)這個(gè)文件路徑是否正確奶躯。最后你會(huì)發(fā)現(xiàn)你指定的文件路徑是完全正確的帚桩。那么問(wèn)題出在哪里了呢?問(wèn)題出在參數(shù)鏈如果要換行書(shū)寫(xiě)嘹黔,每個(gè)參數(shù)指定完成之后必須以\結(jié)尾账嚎,因?yàn)槟J(rèn)參數(shù)鏈?zhǔn)切枰恍袝?shū)寫(xiě)完成的,但是為了書(shū)寫(xiě)的美觀,我們選擇了換行郭蕉,所以每個(gè)參數(shù)指定完成后末尾記得加上\.
到此乏悄,編譯腳本就已經(jīng)解析完成
最后在shell中運(yùn)行編譯腳本,首先在macOS和linux下恳不,需要給編譯文件賦予權(quán)限檩小,不然在編譯過(guò)程中,會(huì)遇到一些權(quán)限問(wèn)題烟勋,這里我們直接最高權(quán)限拉滿
chmod -R 777 build_android.sh
然后為了方便查看日志规求,我們把編譯日志輸出到一個(gè)build_log下
./build_anroid.sh > build_log
編譯成功之后,會(huì)在ffmpeg目錄下出現(xiàn)一個(gè)android目錄卵惦,里面有我們編譯的.so文件阻肿。
至此,ffmpeg編譯已經(jīng)完成沮尿,音視頻的學(xué)習(xí)算是踏出了第一步丛塌,對(duì)于ffmpeg的編譯有什么問(wèn)題,也歡迎各位在評(píng)論區(qū)留言討論畜疾。
另外轉(zhuǎn)載請(qǐng)注明出處赴邻,peace !
參考文獻(xiàn)
http://www.reibang.com/p/117fe2ee048a
https://stackoverflow.com/questions/36664451/ffmpeg-android-build