第三章 FFmpeg的介紹與使用

FFmpeg名稱中的mpeg來自視頻編碼標(biāo)準MPEG,而前綴FF是Fast Forward的首字母縮寫。

目錄

一 FFmpeg的主體結(jié)構(gòu)
二 FFmpeg命令行工具的使用
三 FFmpeg API的介紹與使用

一 FFmpeg的主體結(jié)構(gòu)
image.png

默認的編譯會生成4個可執(zhí)行文件和8個靜態(tài)庫??蓤?zhí)行文件包括用于轉(zhuǎn)碼、推流、Dump媒體文件的ffmpeg、用于播放媒體文件的ffplay、 用于獲取媒體文件信息的ffprobe,以及作為簡單流媒體服務(wù)器的ffserver

8個靜態(tài)庫其實就是FFmpeg的8個模塊,具體包括如下內(nèi)容。

  • AVUtil 核心工具庫,該模塊是最基礎(chǔ)的模塊之一,下面的許多
    其他模塊都會依賴該庫做一些基本的音視頻處理操作。

  • AVFormat 文件格式和協(xié)議庫,該模塊是最重要的模塊之一,封 裝了Protocol層和Demuxer、Muxer層,使得協(xié)議和格式對于開發(fā)者來說是透明的。

  • AVCodec 編解碼庫,該模塊也是最重要的模塊之一,封裝了 Codec層,但是有一些Codec是具備自己的License的,F(xiàn)Fmpeg是不會默認添加像libx264、FDK-AAC、lame等庫的,但是FFmpeg就像一個平臺 一樣,可以將其他的第三方的Codec以插件的方式添加進來,然后為開 發(fā)者提供統(tǒng)一的接口。

  • AVFilter 音視頻濾鏡庫,該模塊提供了包括音頻特效和視頻特效的處理,在使用FFmpeg的API進行編解碼的過程中,直接使用該模塊為音視頻數(shù)據(jù)做特效處理是非常方便同時也非常高效的一種方式。

  • AVDevice 輸入輸出設(shè)備庫,比如,需要編譯出播放聲音或者視頻的工具ffplay,就需要確保該模塊是打開的,同時也需要libSDL的預(yù)先編譯,因為該設(shè)備模塊播放聲音與播放視頻使用的都是libSDL庫。

  • SwrRessample 該模塊可用于音頻重采樣,可以對數(shù)字音頻進行聲道數(shù)、數(shù)據(jù)格式、采樣率等多種基本信息的轉(zhuǎn)換。

  • SWScale 該模塊是將圖像進行格式轉(zhuǎn)換的模塊,比如,可以將 YUV的數(shù)據(jù)轉(zhuǎn)換為RGB的數(shù)據(jù)。

  • PostProc 該模塊可用于進行后期處理,當(dāng)我們使用AVFilter的時候需要打開該模塊的開關(guān),因為Filter中會使用到該模塊的一些基礎(chǔ)函數(shù)。

比如AAC編碼,常見的有兩種封裝格式

  • 一種是ADTS格式的流,是AAC定義在MPEG2里面的格式
  • 另外一種是封裝在MPEG4里面的格式,這種格式會在每一幀前面拼接一個用聲道、采樣率等信息組成的頭。

AACbit 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ù) (其實就是裸的H264的數(shù)據(jù))包。

H264bit stream filter常常應(yīng)用于視頻解碼過程中。

二 FFmpeg命令行工具的使用

ffmpeg是進行媒體文件轉(zhuǎn)碼的命令行工具
ffprobe是用于查看媒體 文件頭信息的工具
ffplay則是用于播放媒體文件的工具

2.1 ffprobe

1.首先用ffprobe查看一個音頻的文件

ffprobe ~/Desktop/32037.mp3

2.輸出格式信息format_name、時間長度duration、文件 大小size、比特率bit_rate、流的數(shù)目nb_streams等。

ffprobe -show_format 32037.mp4

3.以JSON格式的形式輸出具體每一個流最詳細的信息

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其實就是基于ffplay進行改造的播放器,當(dāng)然其做了硬件解碼以及很多兼容性的工作。

音視頻同步

在 ffplay中音畫同步的實現(xiàn)方式其實有三種。分別是

  • 音頻為主時間軸 作為同步源
  • 視頻為主時間軸作為同步源
  • 外部時鐘為主時間軸作為同步源

并且在ffplay中默認的對齊方式也是以音頻為基準進行對齊的。

首先要聲明的是,播放器接收到的視頻幀或者音頻幀,內(nèi)部都會有時間戳(PTS時鐘)來標(biāo)識它實際應(yīng)該在什么時刻進行展示。

實際的對齊策略如下:比較視頻當(dāng)前的播放時間和音頻當(dāng)前的播放時間

  1. 如果視頻播放過快,則通過加大延遲或者重復(fù)播放來降低視頻播放速度;
  2. 如果視頻播放慢了,則通過減小延遲或者丟幀來追趕音頻播放的時間點。

關(guān)鍵就在于音視頻時間的比較以及延遲的計算,當(dāng)然在比較的過程中會設(shè) 置一個閾值(Threshold),若超過預(yù)設(shè)的閾值就應(yīng)該做調(diào)整(丟幀渲染 或者重復(fù)渲染),這就是整個對齊策略。

2.3 ffmpeg

ffmpeg就是強大的媒體文件轉(zhuǎn)換工具。它可以轉(zhuǎn)換任何格式的媒體文件,并且還可以用自己的AudioFilter以及VideoFilter進行處理和編輯。

  1. 從MP4文件中抽取視頻流導(dǎo)出為裸H264數(shù)據(jù)
ffmpeg -i output.mp4 -an -vcodec copy -bsf:v h264_mp4toannexb output.h264
  1. 使用AAC音頻數(shù)據(jù)和H264的視頻生成MP4文件
ffmpeg -i test.aac -i test.h264 -acodec copy -bsf:a aac_adtstoasc -vcodec copy -f mp4 output.mp4
  1. 從WAV音頻文件中導(dǎo)出PCM裸數(shù)據(jù)
ffmpeg -i input.wav -acodec pcm_s16le -f s16le output.pcm
  1. 將兩路聲音進行合并,比如要給一段聲音加上背景音樂
ffmpeg -i vocal.wav -i accompany.wav -filter_complex
           amix=inputs=2:duration=shortest output.wav
  1. 為視頻增加水印效果
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
  1. 將一個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、flvmov等。

  • 媒體流(Stream) 表示時間軸上的一段連續(xù)數(shù)據(jù),如一段聲音數(shù) 據(jù)、一段視頻數(shù)據(jù)或一段字幕數(shù)據(jù),可以是壓縮的,也可以是非壓縮的,壓縮的數(shù)據(jù)需要關(guān)聯(lián)特定的編解碼器。

  • 數(shù)據(jù)幀/數(shù)據(jù)包(Frame/Packet) 通常,一個媒體流是由大量的數(shù)據(jù)幀組成的,對于壓縮數(shù)據(jù),對應(yīng)著編解碼器的最小處理單元,分屬于不同媒體流的數(shù)據(jù)幀交錯存儲于容器之中。

  • 編解碼器 編解碼器是以為單位實現(xiàn)壓縮數(shù)據(jù)原始數(shù)據(jù)之間的相互轉(zhuǎn)換的。

3.2 名詞介紹
  • AVFormatContext就是對容器或者說媒體文件層次的一個抽象。
  • AVStream 對流的抽象
  • AVCodecContextAVCodec對編解碼格式以及編解碼器的抽象
  • AVPacketAVFrame對于編碼器或者解碼器的輸入輸出部分,也就是壓縮數(shù)據(jù)以及原始數(shù)據(jù)的抽象。
  • AVFilter對于音視頻的處理肯定是針對于原始數(shù)據(jù)的處理,也就是針對于AVFrame的處理。
3.3 實例

接下來介紹一個解碼的實例,該實例實現(xiàn)的功能非常單一,就是把一個視頻文件解碼成單獨的音頻PCM文件和視頻YUV文件。

  1. 引用頭文件
  2. 注冊協(xié)議、格式與編解碼器
avformat_network_init();
av_register_all();
  1. 打開媒體文件源,并設(shè)置超時回調(diào)
  2. 尋找各個流,并且打開對應(yīng)的解碼器
  3. 初始化解碼后數(shù)據(jù)的結(jié)構(gòu)體
    分配出解碼之后的數(shù)據(jù)所存放的內(nèi)存空間,以及進行格式轉(zhuǎn)換需要用到的對象
  4. 讀取流內(nèi)容并且解碼
    打開了解碼器之后,就可以讀取一部分流中的數(shù)據(jù)(壓縮數(shù)據(jù)),然后將壓縮數(shù)據(jù)作為解碼器的輸入,解碼器將其解碼為原始數(shù)據(jù)(裸數(shù)據(jù)),之后就可以將原始數(shù)據(jù)寫入文件了。
  5. 處理解碼后的裸數(shù)據(jù)
    解碼之后會得到裸數(shù)據(jù),音頻就是PCM數(shù)據(jù),視頻就是YUV數(shù)據(jù)
  6. 關(guān)閉所有資源
四 FFmpeg源碼結(jié)構(gòu)
4.1 libavformat
image.png

AVFormatContext是API層直接接觸到的結(jié)構(gòu)體,它會進行格式的封 裝與解封裝。

4.2 libavcodec
image.png

該結(jié)構(gòu)體包含的就是與實際的編解碼有關(guān)的部分。

3.3 FFmpeg通用API分析

3.3.1 av_register_all
所以該函數(shù)的內(nèi)部實現(xiàn)會先調(diào)用avcodec_register_all來注冊所有config.h里面開放的編解碼器,然后會注冊所有的MuxerDemuxer(也就是封裝格式),最后注冊所有的Protocol(即協(xié)議層的東西)。

3.3.2 av_find_codec
這里面其實包含了兩部分的內(nèi)容:一部分是尋找解碼器,一部分是尋找編碼器。

3.3.3 avcodec_open2
該函數(shù)是打開編解碼器(Codec)的函數(shù),無論是編碼過程還是解碼過程,都會用到該函數(shù)。

3.4 調(diào)用FFmpeg解碼時用到的函數(shù)分析

avformat_open_input
根據(jù)所提供的文件路徑判斷文件的格 式,其實就是通過這一步來決定使用的到底是哪一個Demuxer。

avformat_find_stream_info
該方法的作用就是把所有StreamMetaData信息填充好。

av_read_frame
使用該方法讀取出來的數(shù)據(jù)是AVPacket。

對于音頻流,一個AVPacket可能包含AVFrame,但是對于視頻流,一個AVPacket只包含AVFrame,該函數(shù)最終只會返回一個AVPacket結(jié)構(gòu)體。

avcodec_decode
該方法包含了兩部分內(nèi)容:一部分是解碼視頻,一部分是解碼音頻,解碼是會委托給對應(yīng)的解碼器來實施的。

avformat_close_input
該函數(shù)負責(zé)釋放對應(yīng)的資源。

3.5 調(diào)用FFmpeg編碼時用到的函數(shù)分析

avformat_alloc_output_context2
該函數(shù)內(nèi)部需要調(diào)用方法avformat_alloc_context來分配一個 AVFormatContext結(jié)構(gòu)體。

avio_open2
編碼的階段了,開發(fā)者需要將手動封裝好的AVFrame結(jié)構(gòu)體,作為avcodec_encode_video方法的輸入,將其編碼成為AVPacket,然后調(diào)用av_write_frame方法輸出到媒體文件中。


本文參考音視頻開發(fā)進階指南


項目源碼地址 - FFmpegDecoder


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,250評論 6 530
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 97,923評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,041評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,475評論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,253評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,801評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,882評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,023評論 0 285
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,530評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,494評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,639評論 1 366
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,177評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 43,890評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,289評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,552評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,242評論 3 389
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,626評論 2 370

推薦閱讀更多精彩內(nèi)容