關(guān)于ffmpeg基礎(chǔ)知識(shí)入門(mén)

關(guān)于ffmpeg

關(guān)于ffmpeg,我們首先需要知道它是什么,ffmpeg官網(wǎng)對(duì)ffmpeg進(jìn)行了定義:

image.png

一個(gè)針對(duì)音視頻的錄制/轉(zhuǎn)換/串流傳輸?shù)目缙脚_(tái)解決方案。

image.png

當(dāng)然,在about頁(yè)面介紹得更加詳細(xì),可以說(shuō)ffmpeg是針對(duì)音視頻領(lǐng)域的全能操作框架。在現(xiàn)如今的互聯(lián)網(wǎng)世界中,關(guān)于音視頻的操作處理,或直接或間接都會(huì)依賴到這個(gè)框架(當(dāng)然也有其他音視頻框架)。

怎樣使用ffmpeg

ffmpeg有兩種使用方法:

  • 自定義開(kāi)發(fā)使用
  • 命令行使用

因?yàn)閒fmpeg的音視頻處理能力都封裝在對(duì)應(yīng)的庫(kù)文件中,因此我們?cè)倏梢栽谧约旱拇a工程中嵌入對(duì)應(yīng)的庫(kù)文件,然后就可以調(diào)用它的基礎(chǔ)能力,通過(guò)各種組合實(shí)現(xiàn)我們想要的功能,這就是自定義開(kāi)發(fā)使用。

而且ffmpeg自身也會(huì)把這些功能庫(kù)統(tǒng)一封裝并套殼,打包成一個(gè)可執(zhí)行文件,可以接受各種輸入命令,比如在windows上就是ffmpeg.exe文件,我們可以下載這個(gè)可執(zhí)行文件,然后再命令行窗口執(zhí)行對(duì)應(yīng)的命令行代碼。

命令行

我們以windows平臺(tái)為例,在官網(wǎng)下載最新的可執(zhí)行文件,不出意外,你會(huì)下載到三個(gè)可執(zhí)行文件,分別是:

  • ffmpeg,用于音視頻進(jìn)行修改(錄制,采集,裁剪,轉(zhuǎn)換等)處理的能力
  • ffprobe,用于分析音視頻文件的相關(guān)信息
  • ffplay,發(fā)播放音視頻

把文件所在路徑添加到系統(tǒng)路徑即可在命令行窗口進(jìn)行調(diào)用。

比如查看媒體文件的一些信息

ffprobe -show_streams sample.mp4 // 顯示sample.mp4內(nèi)部的流的信息

比如視頻文件的格式轉(zhuǎn)換

// mp4轉(zhuǎn)換為avi
ffmpeg -i sample.mp4 -c copy output.avi

命令行的參數(shù)和組合形式非常多,具體可以參考官網(wǎng) Command Line Tools Documentation。

也可以先看看阮一峰 FFmpeg 視頻處理入門(mén)教程,我認(rèn)為他的教程都非常詳細(xì)且易懂

自定義開(kāi)發(fā)

自定義開(kāi)發(fā)則是撇開(kāi)了ffmpeg的殼,只獲取其內(nèi)部功能實(shí)現(xiàn)的庫(kù)文件,把庫(kù)文件集成到我們工程中,通過(guò)調(diào)用ffmpeg提供的API來(lái)實(shí)現(xiàn)我們自己的功能,這個(gè)會(huì)涉及到了c/cpp開(kāi)發(fā)。

關(guān)于自定義開(kāi)發(fā)更多細(xì)節(jié)就不舉例了,這不是本文的重點(diǎn),而且后面會(huì)專門(mén)在ffmpeg的基礎(chǔ)上進(jìn)行功能開(kāi)發(fā)。

小結(jié)

相對(duì)而言命令行的方式更簡(jiǎn)單一些,因?yàn)槊钚邢喈?dāng)于已經(jīng)提前封裝了一些功能實(shí)現(xiàn)的邏輯代碼,自定義開(kāi)發(fā)的使用復(fù)雜的多,因?yàn)樽远x開(kāi)發(fā)則需要自己實(shí)現(xiàn)邏輯。但是自定義開(kāi)發(fā)比較靈活,而且更適合精細(xì)化的,自定義程度較高的那些需求,而且更容易讓我們理解音視頻處理的一些過(guò)程。

其實(shí)這兩種使用方式?jīng)]有本質(zhì)區(qū)別,命令行在library之上增加了中間層,把一些功能實(shí)現(xiàn)凝結(jié)為幾個(gè)命令參數(shù)以達(dá)到簡(jiǎn)化開(kāi)發(fā)的目的。而自定義則直接拿開(kāi)中間層,直接接觸library。

image.png

ffmpeg的功能模塊

image.png
  • libavcodec 提供音視頻的編解碼能力

  • libavformat 提供處理各種音視頻容器格式的能力,比如封裝,解封裝

  • libavutil 提供一些實(shí)用的功能函數(shù)

  • libavfilter 提供音視頻流的濾鏡效果

  • libavdevice 提供操作輸入和輸出設(shè)備的能力。例如,從攝像頭獲取視頻數(shù)據(jù)以及將視頻數(shù)據(jù)輸出到屏幕

  • libswresample 實(shí)現(xiàn)音頻混合和重采樣能力

  • libswscale 實(shí)現(xiàn)視頻幀的顏色轉(zhuǎn)換和縮放能力

如果使用命令行模式,一般會(huì)把上述的庫(kù)全部打包起來(lái),而如果是自定義開(kāi)發(fā)則是按需使用,比如如果不涉及設(shè)備操作可以不要libavdevice,不需要濾鏡功能可以不要libavfilter...

這些支持庫(kù)都是跨平臺(tái)的,既可以是動(dòng)態(tài)庫(kù)也可以是靜態(tài)庫(kù),

ffmpeg的一些基礎(chǔ)概念

time_scale

time_scale 可以稱作時(shí)間刻度,具體的含義是把一秒鐘分為多少個(gè)刻度

time_scale = 10 // 表示把一秒鐘分為10份,10個(gè)刻度,每個(gè)刻度代表1/10秒

time_scale = 1000 // 表示把一秒鐘分為1000份,1000個(gè)刻度,每個(gè)刻度代表1/1000秒

time_base

time_base是ffmpeg中一個(gè)非常重要的概念,一般稱作時(shí)間基,或者可以說(shuō)是ffmpeg中的時(shí)間基礎(chǔ)單位。

現(xiàn)實(shí)世界所使用的時(shí)間基礎(chǔ)單位一般是是秒,因?yàn)槊雽?duì)于普通人而言已經(jīng)足夠精確了,使用毫秒或者微秒毫無(wú)必要,但是在ffmpeg中不是以秒為基礎(chǔ)單位,而是把秒分為若干份,以一份作為ffmpeg中的時(shí)間基礎(chǔ)單位。

time_base = 1/24   //表示把1s分為24份,以1/24作為ffmpeg的時(shí)間的基礎(chǔ)單位。

time_base = 1/1000   //表示把1s分為1000份,以1/1000作為ffmpeg的時(shí)間的基礎(chǔ)單位。

ffmpeg中大量的時(shí)間表示(AVStram,AVPacket,AVFrame中的PTS,DTS),都是以time_base作為基礎(chǔ)單位的,而不是現(xiàn)實(shí)時(shí)間。

PTS/DTS/pts_time

  • DTS(Decoding Time Stamp,解碼時(shí)間戳)

    • 指示解碼器應(yīng)該在什么時(shí)間點(diǎn)開(kāi)始解碼該幀(解碼順序)
  • PTS(Presentation Time Stamp,顯示時(shí)間戳)

    • 指示幀應(yīng)該在什么時(shí)間點(diǎn)被呈現(xiàn)給用戶。PTS 是在解碼后確定的時(shí)間戳,用于視頻幀或音頻幀的渲染或播放順序。
  • pts_time

    • 當(dāng)前媒體幀的顯示時(shí)間,單位為秒

DTS,PTS一般都是以time_base為單位的。

關(guān)于pts,pts_time,time_base之間的計(jì)算方式

time_base = 1/75; 
 Frame        pts           pts_time
   0          0          0 x 1/75 = 0.00  (表示該幀在第0秒顯示)
   1          3          3 x 1/75 = 0.04  (表示該幀在第0.04秒顯示)
   2          6          6 x 1/75 = 0.08  (表示該幀在第0.08秒顯示)
   3          9          9 x 1/75 = 0.12  (表示該幀在第0.12秒顯示)

AVStream

在ffmpeg中,讀取或者寫(xiě)入視頻文件時(shí),內(nèi)部會(huì)構(gòu)建一個(gè)數(shù)據(jù)結(jié)構(gòu)AVFormatContext,這個(gè)結(jié)構(gòu)中包含了視頻的相關(guān)信息,其中一個(gè)信息就是AVStram數(shù)組,每一個(gè)AVStream都包含了一種數(shù)據(jù),比如音頻和視頻分別代表一個(gè)AVStram結(jié)構(gòu),我們可以從中獲取比如時(shí)長(zhǎng),幀數(shù),編解碼器信息,time_base等

image.png

一旦我們獲取了AVStream,我們就可以讀取該Stream所代表的數(shù)據(jù)。

AVPacket

在ffmpeg中,在視頻文件讀取到基本信息之后,就可以讀取正式數(shù)據(jù)內(nèi)容用于解碼,而這個(gè)用于解碼的數(shù)據(jù)格式就是AVPacket.

AVPakcet內(nèi)部包括待一段解碼的數(shù)據(jù)data,size,pts,dts,time_base,stream_id(表示packet讀取自哪個(gè)AVStream)等。

image.png

AVFrame

AVFrame則是解碼后的原始數(shù)據(jù),表示一個(gè)可以被使用幀,注意這并不一定是視頻幀,也可能是音頻幀,因?yàn)橐曨l和音頻都使用AVFrame的數(shù)據(jù)結(jié)構(gòu)。

AVFrame內(nèi)包含可播放數(shù)據(jù),寬,高(視頻),幀類型(視頻),采樣數(shù)(音頻),音頻格式,PTS等

一般如果是視頻,AVFrame表示得是YUV或者RGB圖片;如果是音頻,則AVFrame表示得是PCM數(shù)據(jù)。

image.png

此時(shí)的得到的數(shù)據(jù)可以直接被播放。

音視頻同步

在獲得了可用的音頻或者視頻幀之后,也并不是直接發(fā)送到對(duì)應(yīng)的設(shè)備進(jìn)行播放即可,一般需要我們進(jìn)行音視頻同步控制,因?yàn)闀?huì)出現(xiàn)音頻和視頻因?yàn)楦鞣N差異導(dǎo)致獲得可用幀的速度差別很大,比如視頻很快播放完,但是音頻才播了一點(diǎn)點(diǎn)。因此我們需要通過(guò)PTS和time_base來(lái)控制每一幀的播放速度。

至于同步方法,一般是需要建立一個(gè)時(shí)間坐標(biāo)系作為參考,然后計(jì)算每一幀的顯示時(shí)間戳是否對(duì)應(yīng)了正確的時(shí)間,否則就等待。

邏輯流程與數(shù)據(jù)格式轉(zhuǎn)換

根據(jù)上面的對(duì)一些數(shù)據(jù)類型的簡(jiǎn)單介紹,我們已經(jīng)可以得到一個(gè)音頻文件播放過(guò)程的邏輯流程了

image.png

同樣的,把可播放的原始數(shù)據(jù)保存成文件則是這個(gè)過(guò)程的逆過(guò)程,大同小異。

總結(jié)

本文主要對(duì)ffmpeg使用方法,核心模塊,ffmpeg中的一些基本概念做了介紹,后面將會(huì)站在自定義開(kāi)發(fā)的角度上,分析ffmpeg的數(shù)據(jù)結(jié)構(gòu)的詳情,和一個(gè)視頻被播放的完整過(guò)程實(shí)現(xiàn),最終會(huì)講講在Android平臺(tái)的使用方式。

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

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

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