前言
看了前面的一些C/C++基礎(chǔ)以及一些編譯基礎(chǔ),那現(xiàn)在是時(shí)候?qū)崙?zhàn)一下,這里就編譯順便看一下FFmpeg的大體結(jié)構(gòu)。
正文
這里就邊操作,邊記錄吧,來看看大名鼎鼎的FFmpeg庫。
相關(guān)推薦
Android音視頻開發(fā):音視頻基礎(chǔ)知識(shí)到直播推流實(shí)戰(zhàn)系列教程_嗶哩嗶哩_bilibili
FFmpeg定義
FFmpeg既是一款音視頻編解碼工具,同時(shí)也是一組音視頻編解碼開發(fā)套件,作為編解碼開發(fā)套件,為開發(fā)者提供了豐富的音視頻處理的調(diào)用接口。
FFmpeg提供了多種媒體格式的封裝和解封裝,包含多種音視頻編解碼、多種協(xié)議的流媒體、多種色彩格式轉(zhuǎn)換、多種采樣率轉(zhuǎn)換、多種碼率轉(zhuǎn)換等等。
同時(shí)FFmpeg框架提供了多種豐富的插件模塊,包含封裝與解封裝插件、編碼與解碼的插件等。
關(guān)于這里的一些具體概念,比如什么是封裝和解封裝,我們到后面學(xué)習(xí)音視頻相關(guān)知識(shí)點(diǎn)就明白了,這里先大概了解。
FFmpeg模塊介紹
關(guān)于下載FFmpeg代碼很容易,從官網(wǎng)或者GitHub都可以,但是我嘗試了在Linux上下載很慢,所以我直接在Windows上在GitHub下載了,拷貝到了Linux虛擬機(jī)中,下面就是完整的目錄:

FFmpeg框架的目錄還是蠻清晰的,其中包括了幾個(gè)模塊,這里先簡單介紹一下:
- libavcodec
編解碼庫,封裝了Codec層,但是有一些codec是具備自己的License,F(xiàn)Fmpeg不會(huì)默認(rèn)添加,比如libx264、FDK-AAC、Lame等庫,但是FFmpeg像是一個(gè)平臺(tái),可以降其他第三方codec以插件的方式添加進(jìn)來,為開發(fā)者提供統(tǒng)一接口。
- libavformat
文件格式和協(xié)議庫,封裝了Protocol層和Demuxer、Muxer層,使得協(xié)議和格式對于開發(fā)者來說是透明的。
- libavfilter
音視頻濾鏡庫,該模塊包含了音視頻特效的處理,在使用FFmpeg的API進(jìn)行編解碼的過程中,可以使用該模塊高效的為音視頻數(shù)據(jù)做特殊處理。
- libavdevice
輸入輸出設(shè)備庫,比如需要編譯出播放聲音或者視頻的工具ffplay,就需要確保該模塊是打開的,同時(shí)也需要libsdl的預(yù)先編譯,該設(shè)備模塊播放聲音和視頻又都是使用libsdl庫。
- libavutil
核心工具庫,最基礎(chǔ)模塊之一,其他模塊都會(huì)依賴該模塊做一些基本的音視頻處理操作。
- libswresample
用于音視頻采樣,可以對音頻進(jìn)行聲道數(shù)、數(shù)據(jù)格式、采樣率等多種基本信息的轉(zhuǎn)換。
- libswscale
該模塊用于圖像格式轉(zhuǎn)換,可以降YUV的數(shù)據(jù)轉(zhuǎn)換為RGB的數(shù)據(jù)
- libpostproc
該模塊用于后期處理,當(dāng)我們使用filter的時(shí)候,就需要打開這個(gè)模塊,filter會(huì)用到這個(gè)模塊的一些基礎(chǔ)函數(shù)。
另外,庫里還包含對H.264/MPEG-4 AVC視頻編碼的X264庫,是非常常用的有損視頻編碼器,支持CBR、VBR模塊,可以在編碼的過程中直接改變碼率的設(shè)置,在直播場景中非常適用,可以做碼率自適應(yīng)的功能。
一些最基本的介紹就是上面了,具體是啥意思,我們后面再細(xì)說。
編譯FFmpeg
wget命令
在Linux中可以使用wget命令來下載文件,這個(gè)wget就相當(dāng)于是一個(gè)下載器,但是呢最近發(fā)現(xiàn)很多網(wǎng)站使用wget下載特別慢,尤其是國外的一些網(wǎng)站,Windows掛了代理也還是不行,上網(wǎng)找了一些,推薦使用mwget。
mwget命令
mwget下載器是一個(gè)多線程下載應(yīng)用,比wget下載更快,下面有個(gè)腳本可以直接安裝:
#!/bin/bashwget http://jaist.dl.sourceforge.net/project/kmphpfm/mwget/0.1/mwget_0.1.0.orig.tar.bz2
yum install bzip2 gcc-c++ openssl-devel intltool -y
bzip2 -d mwget_0.1.0.orig.tar.bz2
tar -xvf mwget_0.1.0.orig.tar
cd mwget_0.1.0.orig
./configure #一般用來生成 Makefile,為下一步的編譯做準(zhǔn)備,你可以通過在 configure 后加上參數(shù)來對安裝進(jìn)行控制,比如代碼:./configure –prefix=/usr 意思是將該軟件安裝在/usr下面
make #編譯,大多數(shù)的源代碼包都經(jīng)過這一步進(jìn)行編譯
make install #開始安裝echo "至此,安裝完成"
這個(gè)腳本在Ubuntu上肯定運(yùn)行不起來,就比如yum這個(gè)命令在Ubuntu上就不行,這里就簡單介紹一下apt和yum。
apt和yun
一般來說著名的Linux系統(tǒng)分為2大類,
RedHat系列:Redhat、Centos、Fedora等
Debian系列:Debian、Ubuntu等
這2個(gè)系統(tǒng)的包管理器用的是不一樣的,有區(qū)分yum、dkpg和apt,下圖是區(qū)別:

所以上面yum安裝bzip2的命令就需要修改一下,改成
apt install bzip2 gcc-c++ openssl-devel intltool -y
但是呢,會(huì)發(fā)現(xiàn)這4個(gè)軟件只有一個(gè)bzip2能安裝成功,其他幾個(gè)都找不到,這又是什么鬼呢,下面再來細(xì)說。
Ubuntu安裝mwget
這里還是單獨(dú)說一下在Ubuntu下安裝這個(gè)mwget,因?yàn)榫W(wǎng)上很多都是centos系統(tǒng),直接看一個(gè)鏈接:
會(huì)發(fā)現(xiàn)想跑通mwget的shell腳本需要安裝3個(gè)軟件,然后把壓縮包bz2文件先進(jìn)行解壓,然后運(yùn)行./configure腳本,這個(gè)腳本跑完后需要執(zhí)行make和make install,注意這又是坑,首先需要sudo權(quán)限,然后會(huì)發(fā)現(xiàn)很多cpp文件缺少頭文件,這時(shí)需要挨個(gè)去修改添加頭文件。
下載FFmpeg
假設(shè)上面mwget能成功安裝,這時(shí)就需要下載和解壓FFmpeg了,命令如下:
mwget https://ffmpeg.org/releases/ffmpeg-4.2.2.tar.bz2
tar -jxvf ffmpeg-4.2.2.tar.bz2
下載完之后,就是上面我們簡單介紹的幾個(gè)目錄了,這時(shí)可以直接運(yùn)行configure腳本,這個(gè)腳本是用來配置FFmpeg的,里面配置項(xiàng)巨多,我們可以直接運(yùn)行:

這里發(fā)現(xiàn)居然執(zhí)行不過,原因很簡單,是因?yàn)闆]有yasm匯編編譯器,F(xiàn)Fmpeg為了提高效率使用了匯編指令,所以需要安裝匯編編譯器:
sudo apt-get install yasm
即可,然后configure腳本就可以執(zhí)行成功。
編譯FFmpeg
當(dāng)然上面腳本編譯時(shí)是編譯很多東西,我們需要針對我們自己的需求,定制一個(gè)腳本,其實(shí)就是配置FFmpeg的configure中的各種選項(xiàng),下面我們來看一下:
#!/bin/bash
echo ">>>>>>>>> 注意:該編譯環(huán)境目前只在 NDK17c + ffmpeg4.2.2 測試過 <<<<<<<<"
echo ">>>>>>>>> 注意:該編譯環(huán)境目前只在 NDK17c + ffmpeg4.2.2 測試過 <<<<<<<<"
echo ">>>>>>>>> 注意:該編譯環(huán)境目前只在 NDK17c + ffmpeg4.2.2 測試過 <<<<<<<<"
#NDK_ROOT 變量指向 ndk 目錄
NDK_ROOT=$NDK_HOME
#指定android api版本
ANDROID_API=21
#開始編譯 在下面調(diào)用傳入?yún)?shù)即可
function build_ffmpeg()
{
echo "開始編譯 $PREFIX_CPU"
echo "開始編譯 $PREFIX"
echo "開始編譯 $TOOLCHAIN"
./configure \
--prefix=$PREFIX \
--enable-small \
--disable-programs \
--disable-avdevice \
--disable-encoders \
--disable-muxers \
--disable-filters \
--enable-cross-compile \
--cross-prefix=$CROSS_PREFIX \
--disable-shared \
--enable-static \
--sysroot=$NDK_ROOT/platforms/android-$ANDROID_API/arch-$ARCH \
--extra-cflags="$CFLAGES" \
--arch=$ARCH \
--target-os=android
#上面運(yùn)行腳本生成makefile之后,使用make執(zhí)行腳本
make clean
make
make install
echo "$PREFIX_CPU 編譯完成"
echo "$PREFIX_CPU 編譯完成"
echo "$PREFIX_CPU 編譯完成"
}
#armeabi-v7a
PREFIX=./result/armeabi-v7a
TOOLCHAIN=$NDK_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
ARCH=arm
CROSS_PREFIX=$TOOLCHAIN/bin/arm-linux-androideabi-
CFLAGES="-isysroot $NDK_ROOT/sysroot -isystem $NDK_ROOT/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=$ANDROID_API -U_FILE_OFFSET_BITS -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -O0 -fPIC"
build_ffmpeg
#arm64-v8a
PREFIX=./result/arm64-v8a
TOOLCHAIN=$NDK_ROOT/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64
ARCH=arm64
CROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android-
CFLAGES="-isysroot $NDK_ROOT/sysroot -isystem $NDK_ROOT/sysroot/usr/include/aarch64-linux-android -D__ANDROID_API__=$ANDROID_API -U_FILE_OFFSET_BITS -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wa,--noexecstack -Wformat -Werror=format-security -O0 -fPIC"
build_ffmpeg
#直接跳轉(zhuǎn)到編譯完成的路徑
cd /result
上面就是編譯的腳本,這里有幾點(diǎn)需要說明一下,對于這種編譯的腳本,還是要力求都看懂,不然出問題了根本無法查找。
- 就是變量問題,比如這里的PREFIX、TOOLCHAIN、ARCH這3個(gè)變量就是有的是新建的目錄、有的就是字符串。
- 這里函數(shù)參數(shù)也要注意,比如工具鏈、CPU架構(gòu)版本等等。
- 這里可以在shell腳本中使用函數(shù),其中和運(yùn)行shell腳本一樣可以直接在腳本名后面?zhèn)鬟f參數(shù)一樣,這里可以直接定義build_ffmpeg()函數(shù),然后在后面進(jìn)行調(diào)用。
- 其中在build_ffmpeg函數(shù)中,就是調(diào)用FFmpeg的configure腳本,并且傳入一些列參數(shù)來配置這個(gè)腳本,關(guān)于這個(gè)腳本,后面還可以細(xì)說一下里面的常用配置。
- 在運(yùn)行完configure后,會(huì)生成一個(gè)makefile文件,然后通過make指令可以執(zhí)行腳本。
configure常用參數(shù)
既然我們知道了這里的編譯腳本就是配置configure中的一些配置,那常用的配置我們必須得懂,下面就羅列一些:
- --prefix=PREFIX:設(shè)置動(dòng)、靜態(tài)庫的位置,這個(gè)必須設(shè)置。
- --enable-small:可以優(yōu)化庫的大小。
- --disable-programs:我們不需要使用程序也就是不需要在Windows執(zhí)行某個(gè).exe程序,我們只在代碼中使用。
- --disable-avdevice:可以操控我們的攝像頭,Android中是不支持。
- --disable-encoders:編碼是否打開,這里為了編譯更快,如果用不到可以去掉。
- --disable-muxers:混合封裝是否可以打開,如果不用可以去掉。
- --disable-filters:濾鏡特效等是否開啟,如果不用可以去掉。
- --enable-cross-compile:開啟交叉編譯。
- --cross-prefix=$CROSS_PREFIX:交叉編譯的腳本,也就是前面設(shè)置的NDK里的編譯腳本。
- --disable-shared:是否開啟編譯成動(dòng)態(tài)庫。
- --enable-static:是否開啟編譯成靜態(tài)庫。
- --sysroot=NDKROOT/platforms/android?NDK_ROOT/platforms/android-NDKROOT/platforms/android?ANDROID_API/arch-$ARCH:交叉編譯的一些配置。
- --extra-cflags="$CFLAGES":其他的一些配置。
- --arch=$ARCH:期望的運(yùn)行環(huán)境的CPU架構(gòu)
- --target-os=android:期望運(yùn)行在Android平臺(tái)。
編譯問題
首先這個(gè)編譯可不是一帆風(fēng)順的,由于代碼太多,我的Ubuntu虛擬機(jī)大概要編譯20分鐘,其中有幾個(gè)主要錯(cuò)誤,下面來說一下。
- C compiler test failed:c編譯器錯(cuò)誤,這個(gè)原因主要是FFmpeg 4.2.2版本開始默認(rèn)使用clang進(jìn)行編譯,這需要找到configure中的代碼進(jìn)行修改默認(rèn)配置:
//1. 修改 configure 文件
vim configure
//2. 把 默認(rèn)的 clang 修改為 gcc
if test "$target_os" = android; then
# cc_default="clang"
cc_default="gcc"
fi
yasm not found:這個(gè)之前也說過,無法找到匯編編譯器,需要安裝即可。
vim中如何查找關(guān)鍵字,這個(gè)是vim的一個(gè)操作,在命令模式下,輸入 /xxx 即可查找xxx,并且可以高亮顯示,想查看下一個(gè)按 n 鍵即next可以查看下一個(gè)xxx關(guān)鍵字,這個(gè)在查找長腳本文件中很關(guān)鍵。
總結(jié)
編譯FFmpeg還是很復(fù)雜的,這也正常,畢竟FFmpeg有這么多功能,音視頻學(xué)習(xí)之路還很長,邊學(xué)邊總結(jié)吧,加油。
相關(guān)推薦
Android音視頻開發(fā):音視頻基礎(chǔ)知識(shí)到直播推流實(shí)戰(zhàn)系列教程_嗶哩嗶哩_bilibili
本文轉(zhuǎn)自 https://juejin.cn/post/7025441094921879560,如有侵權(quán),請聯(lián)系刪除。