音視頻學(xué)習(xí)之路--編譯FFmpeg

前言

看了前面的一些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è)鏈接:

# Ubuntu安裝mwget

會(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)系刪除。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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