FFmpeg名稱中的mpeg來自視頻編碼標(biāo)準(zhǔn)MPEG岛抄,而前綴FF是Fast Forward的首字母縮寫别惦。
目錄
一 FFmpeg的主體結(jié)構(gòu)
二 FFmpeg命令行工具的使用
三 FFmpeg API的介紹與使用
一 FFmpeg的主體結(jié)構(gòu)
默認(rèn)的編譯會(huì)生成4
個(gè)可執(zhí)行文件和8
個(gè)靜態(tài)庫》蛲郑可執(zhí)行文件包括用于轉(zhuǎn)碼
掸掸、推流
、Dump媒體文件的ffmpeg
、用于播放媒體文件的ffplay
扰付、 用于獲取媒體文件信息的ffprobe
堤撵,以及作為簡單流媒體服務(wù)器的ffserver
。
8個(gè)靜態(tài)庫其實(shí)就是FFmpeg的8個(gè)模塊羽莺,具體包括如下內(nèi)容实昨。
AVUtil
核心工具庫,該模塊是最基礎(chǔ)
的模塊之一盐固,下面的許多
其他模塊都會(huì)依賴該庫做一些基本的音視頻處理操作荒给。AVFormat
文件格式和協(xié)議庫,該模塊是最重要的模塊之一刁卜,封 裝了Protocol層和Demuxer志电、Muxer層,使得協(xié)議和格式對于開發(fā)者來說是透明的蛔趴。AVCodec
編解碼庫挑辆,該模塊也是最重要的模塊之一,封裝了 Codec層孝情,但是有一些Codec是具備自己的License的鱼蝉,F(xiàn)Fmpeg是不會(huì)默認(rèn)添加像libx264、FDK-AAC咧叭、lame等庫的蚀乔,但是FFmpeg就像一個(gè)平臺 一樣,可以將其他的第三方的Codec以插件的方式添加進(jìn)來菲茬,然后為開 發(fā)者提供統(tǒng)一的接口吉挣。AVFilter
音視頻濾鏡庫,該模塊提供了包括音頻特效和視頻特效的處理婉弹,在使用FFmpeg的API進(jìn)行編解碼的過程中睬魂,直接使用該模塊為音視頻數(shù)據(jù)做特效處理是非常方便同時(shí)也非常高效的一種方式。AVDevice
輸入輸出設(shè)備庫镀赌,比如氯哮,需要編譯出播放聲音或者視頻的工具ffplay
,就需要確保該模塊是打開的商佛,同時(shí)也需要libSDL的預(yù)先編譯喉钢,因?yàn)樵撛O(shè)備模塊播放聲音與播放視頻使用的都是libSDL庫。SwrRessample
該模塊可用于音頻重采樣
良姆,可以對數(shù)字音頻進(jìn)行聲道數(shù)肠虽、數(shù)據(jù)格式、采樣率等多種基本信息的轉(zhuǎn)換玛追。SWScale
該模塊是將圖像進(jìn)行格式轉(zhuǎn)換
的模塊税课,比如闲延,可以將 YUV的數(shù)據(jù)轉(zhuǎn)換為RGB的數(shù)據(jù)。PostProc
該模塊可用于進(jìn)行后期處理韩玩,當(dāng)我們使用AVFilter的時(shí)候需要打開該模塊的開關(guān)垒玲,因?yàn)镕ilter中會(huì)使用到該模塊的一些基礎(chǔ)函數(shù)。
比如AAC編碼找颓,常見的有兩種封裝格式
- 一種是ADTS格式的流合愈,是AAC定義在MPEG2里面的格式
- 另外一種是封裝在MPEG4里面的格式,這種格式會(huì)在每一幀前面拼接一個(gè)用聲道叮雳、采樣率等信息組成的頭想暗。
AAC
的bit stream filter
常常應(yīng)用在編碼
的過程中。
與音頻的AAC編碼格式相對應(yīng)的是視頻中的H264編碼
帘不,它也有兩種封裝格式
- 一種是 MP4封裝的格式
- 一種是裸的H264格式(一般稱為annexb封裝格式)
FFmpeg中也提供了對應(yīng)的bit stream filter
,稱H264_mp4toannexb
杨箭,可以將MP4封裝格式的H264數(shù)據(jù)包轉(zhuǎn)換為annexb封裝格式的H264數(shù)據(jù) (其實(shí)就是裸的H264的數(shù)據(jù))包寞焙。
H264
的bit stream filter
常常應(yīng)用于視頻解碼過程中。
二 FFmpeg命令行工具的使用
ffmpeg
是進(jìn)行媒體文件轉(zhuǎn)碼的命令行工具
ffprobe
是用于查看媒體 文件頭信息的工具
ffplay
則是用于播放媒體文件的工具
2.1 ffprobe
1.首先用ffprobe查看一個(gè)音頻的文件
ffprobe ~/Desktop/32037.mp3
2.輸出格式信息format_name互婿、時(shí)間長度duration捣郊、文件 大小size、比特率bit_rate慈参、流的數(shù)目nb_streams等呛牲。
ffprobe -show_format 32037.mp4
3.以JSON格式的形式輸出具體每一個(gè)流最詳細(xì)
的信息
ffprobe -print_format json -show_streams 32037.mp4
4.顯示幀信息的命令如下:
ffprobe -show_frames sample.mp4
5.查看包信息的命令如下:
ffprobe -show_packets sample.mp4
2.2 ffplay
ffplay是以FFmpeg框架為基礎(chǔ),外加渲染音視頻 的庫libSDL來構(gòu)建的媒體文件播放器驮配。
業(yè)界內(nèi)開源的ijkPlayer
其實(shí)就是基于ffplay
進(jìn)行改造的播放器娘扩,當(dāng)然其做了硬件解碼以及很多兼容性的工作。
音視頻同步
在 ffplay中音畫同步的實(shí)現(xiàn)方式其實(shí)有三種壮锻。分別是
- 以
音頻
為主時(shí)間軸 作為同步源 - 以
視頻
為主時(shí)間軸作為同步源 - 以
外部時(shí)鐘
為主時(shí)間軸作為同步源
并且在ffplay
中默認(rèn)的對齊方式也是以音頻
為基準(zhǔn)進(jìn)行對齊的琐旁。
首先要聲明的是,播放器接收到的視頻幀或者音頻幀猜绣,內(nèi)部都會(huì)有時(shí)間戳(PTS時(shí)鐘)
來標(biāo)識它實(shí)際應(yīng)該在什么時(shí)刻進(jìn)行展示灰殴。
實(shí)際的對齊策略如下:比較視頻當(dāng)前的播放時(shí)間和音頻當(dāng)前的播放時(shí)間
- 如果視頻播放
過快
,則通過加大延遲或者重復(fù)播放來降低視頻播放速度; - 如果視頻播
放慢
了掰邢,則通過減小延遲或者丟幀來追趕音頻播放的時(shí)間點(diǎn)牺陶。
關(guān)鍵就在于音視頻時(shí)間的比較以及延遲的計(jì)算,當(dāng)然在比較的過程中會(huì)設(shè) 置一個(gè)閾值(Threshold)
辣之,若超過預(yù)設(shè)的閾值就應(yīng)該做調(diào)整(丟幀渲染 或者重復(fù)渲染)掰伸,這就是整個(gè)對齊策略。
2.3 ffmpeg
ffmpeg
就是強(qiáng)大的媒體文件轉(zhuǎn)換工具召烂。它可以轉(zhuǎn)換任何格式的媒體文件碱工,并且還可以用自己的AudioFilter
以及VideoFilter
進(jìn)行處理和編輯。
- 從MP4文件中抽取視頻流導(dǎo)出為裸H264數(shù)據(jù)
ffmpeg -i output.mp4 -an -vcodec copy -bsf:v h264_mp4toannexb output.h264
- 使用AAC音頻數(shù)據(jù)和H264的視頻生成MP4文件
ffmpeg -i test.aac -i test.h264 -acodec copy -bsf:a aac_adtstoasc -vcodec copy -f mp4 output.mp4
- 從WAV音頻文件中導(dǎo)出PCM裸數(shù)據(jù)
ffmpeg -i input.wav -acodec pcm_s16le -f s16le output.pcm
- 將兩路聲音進(jìn)行合并,比如要給一段聲音加上背景音樂
ffmpeg -i vocal.wav -i accompany.wav -filter_complex
amix=inputs=2:duration=shortest output.wav
- 為視頻增加水印效果
ffmpeg -i input.mp4 -i changba_icon.png -filter_complex
'[0:v][1:v]overlay=main_w-overlay_w-10:10:1[out]' -map '[out]' output.mp4
- 將一個(gè)YUV格式表示的數(shù)據(jù)轉(zhuǎn)換為JPEG格式的圖片
ffmpeg -f rawvideo -pix_fmt yuv420p -s 480*480 -i texture.yuv -f image2-vcodec mjpeg output.jpg
三 FFmpeg API的介紹與使用
3.1 術(shù)語
容器/文件(Conainer/File)
即特定格式的多媒體文件,比如MP4
、flv
伯襟、mov
等沪蓬。媒體流(Stream)
表示時(shí)間軸上的一段連續(xù)數(shù)據(jù),如一段聲音數(shù) 據(jù)蚓庭、一段視頻數(shù)據(jù)或一段字幕數(shù)據(jù),可以是壓縮的,也可以是非壓縮的春弥,壓縮的數(shù)據(jù)需要關(guān)聯(lián)特定的編解碼器
。數(shù)據(jù)幀/數(shù)據(jù)包(Frame/Packet)
通常叠荠,一個(gè)媒體流是由大量的數(shù)據(jù)幀組成的匿沛,對于壓縮數(shù)據(jù),幀
對應(yīng)著編解碼器
的最小處理單元榛鼎,分屬于不同媒體流的數(shù)據(jù)幀交錯(cuò)存儲于容器之中逃呼。編解碼器
編解碼器是以幀
為單位實(shí)現(xiàn)壓縮數(shù)據(jù)
和原始數(shù)據(jù)
之間的相互轉(zhuǎn)換的。
3.2 名詞介紹
-
AVFormatContext
就是對容器或者說媒體文件層次的一個(gè)抽象者娱。 -
AVStream
對流的抽象 -
AVCodecContext
與AVCodec
對編解碼格式以及編解碼器的抽象 -
AVPacket
與AVFrame
對于編碼器或者解碼器的輸入輸出部分抡笼,也就是壓縮數(shù)據(jù)以及原始數(shù)據(jù)的抽象。 -
AVFilter
對于音視頻的處理肯定是針對于原始數(shù)據(jù)的處理黄鳍,也就是針對于AVFrame
的處理推姻。
3.3 實(shí)例
接下來介紹一個(gè)解碼的實(shí)例,該實(shí)例實(shí)現(xiàn)的功能非常單一框沟,就是把一個(gè)視頻文件解碼成單獨(dú)的音頻PCM文件和視頻YUV文件藏古。
- 引用頭文件
- 注冊協(xié)議、格式與編解碼器
avformat_network_init();
av_register_all();
- 打開媒體文件源街望,并設(shè)置超時(shí)回調(diào)
- 尋找各個(gè)流校翔,并且打開對應(yīng)的解碼器
- 初始化解碼后數(shù)據(jù)的結(jié)構(gòu)體
分配出解碼之后的數(shù)據(jù)所存放的內(nèi)存空間,以及進(jìn)行格式轉(zhuǎn)換需要用到的對象 - 讀取流內(nèi)容并且解碼
打開了解碼器之后灾前,就可以讀取一部分流中的數(shù)據(jù)(壓縮數(shù)據(jù)
)防症,然后將壓縮數(shù)據(jù)作為解碼器
的輸入,解碼器將其解碼為原始數(shù)據(jù)
(裸數(shù)據(jù)
)哎甲,之后就可以將原始數(shù)據(jù)寫入文件了蔫敲。 - 處理解碼后的裸數(shù)據(jù)
解碼之后會(huì)得到裸數(shù)據(jù),音頻就是PCM
數(shù)據(jù)炭玫,視頻就是YUV
數(shù)據(jù) - 關(guān)閉所有資源
四 FFmpeg源碼結(jié)構(gòu)
4.1 libavformat
AVFormatContext是API層直接接觸到的結(jié)構(gòu)體奈嘿,它會(huì)進(jìn)行格式的封 裝與解封裝。
4.2 libavcodec
該結(jié)構(gòu)體包含的就是與實(shí)際的編解碼
有關(guān)的部分吞加。
3.3 FFmpeg通用API分析
3.3.1 av_register_all
所以該函數(shù)的內(nèi)部實(shí)現(xiàn)會(huì)先調(diào)用avcodec_register_all
來注冊所有config.h里面開放的編解碼器裙犹,然后會(huì)注冊所有的Muxer
和Demuxer
(也就是封裝格式)尽狠,最后注冊所有的Protocol
(即協(xié)議層的東西)。
3.3.2 av_find_codec
這里面其實(shí)包含了兩部分的內(nèi)容:一部分是尋找解碼器
叶圃,一部分是尋找編碼器
袄膏。
3.3.3 avcodec_open2
該函數(shù)是打開編解碼器(Codec)的函數(shù),無論是編碼過程還是解碼過程掺冠,都會(huì)用到該函數(shù)沉馆。
3.4 調(diào)用FFmpeg解碼時(shí)用到的函數(shù)分析
avformat_open_input
根據(jù)所提供的文件路徑判斷文件的格 式,其實(shí)就是通過這一步來決定使用的到底是哪一個(gè)Demuxer
德崭。
avformat_find_stream_info
該方法的作用就是把所有Stream
的MetaData
信息填充好斥黑。
av_read_frame
使用該方法讀取出來的數(shù)據(jù)是AVPacket
。
對于音頻流
眉厨,一個(gè)AVPacket
可能包含多
個(gè)AVFrame
锌奴,但是對于視頻流
,一個(gè)AVPacket
只包含一
個(gè)AVFrame
憾股,該函數(shù)最終只會(huì)返回一個(gè)AVPacket
結(jié)構(gòu)體缨叫。
avcodec_decode
該方法包含了兩部分內(nèi)容:一部分是解碼視頻
,一部分是解碼音頻
荔燎,解碼
是會(huì)委托給對應(yīng)的解碼器來實(shí)施的。
avformat_close_input
該函數(shù)負(fù)責(zé)釋放對應(yīng)的資源销钝。
3.5 調(diào)用FFmpeg編碼時(shí)用到的函數(shù)分析
avformat_alloc_output_context2
該函數(shù)內(nèi)部需要調(diào)用方法avformat_alloc_context來分配一個(gè) AVFormatContext
結(jié)構(gòu)體有咨。
avio_open2
編碼的階段了,開發(fā)者需要將手動(dòng)封裝好的AVFrame
結(jié)構(gòu)體蒸健,作為avcodec_encode_video
方法的輸入座享,將其編碼成為AVPacket
,然后調(diào)用av_write_frame
方法輸出到媒體文件中似忧。