FFMPEG libs結(jié)構(gòu)及其分析

這個(gè)系列 并不是給主播看的。所以,不適合的人,麻煩跑路吧~ 之后會(huì)更新直播推流的系列給大家調(diào)極致的畫(huà)面體驗(yàn)???(那個(gè)系列尚在腦海中瞎想,成型了再寫(xiě))
最近再寫(xiě)一些轉(zhuǎn)碼相關(guān)的東東→_→,由于工作原因 不大可能把整段代碼往出貼。一點(diǎn)點(diǎn)寫(xiě),也給自己做個(gè)記錄。盡量能讓門(mén)外漢看懂的基本知識(shí),麻煩各類大神也請(qǐng)跑路吧~
其實(shí)不貼代碼的原因是,在網(wǎng)上看別人代碼的時(shí)候發(fā)現(xiàn)大部分根本跑不通,步驟都是少了的不是沒(méi)分配內(nèi)存,就是少了某一步,看完就覺(jué)得辣雞,都沒(méi)心情看下去,居然還炒來(lái)炒去。。呵呵。所以?只記錄原理 不記錄代碼 代碼細(xì)節(jié)可以看以上那些文章仔細(xì)調(diào)完錯(cuò)然后寫(xiě)寫(xiě)看。
這篇主要記錄轉(zhuǎn)碼相關(guān)的libs 后面細(xì)說(shuō)
先看看轉(zhuǎn)碼流程?
? ? ? ? ? ? ? ? ? ?輸入
????????? ? ? ? ? ? ?↓
?????????????????demux
???↓? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ↓
音頻? ? ? ? ? ? ? ? ? ? ? ? ? ? 視頻
? ?↓? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ↓
解碼? ? ? ? ? ? ? ? ? ? ? ? ? ? 解碼
? ?↓? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ↓
處理? ? ? ? ? ? ? ? ? ? ? ? ? ? 處理
? ?↓? ??? ? ? ? ? ? ? ? ? ? ? ??? ??↓
編碼? ? ? ? ? ? ? ? ? ? ? ? ? ? 編碼
? ?????????????????↓?
????????????? ? ?mux
????????????????? ?↓
?????????????????輸出?
輸入
就是你的輸入流~由于寫(xiě)的直播相關(guān),所以用的是rtmp的拉流。當(dāng)然還可以讀取視頻文件,比如flv mp4等等。此時(shí)比較重要的function : avformat_open_input 拿來(lái)給結(jié)構(gòu)體,AVFormatContext讀取和賦值,以便于下一步demux(拆包使用),基本你的格式頭到了,這玩意就能讀出來(lái)東西了。至于格式頭長(zhǎng)得個(gè)啥德行,以FLV為例
46 4C 56 01 05 00 00 00 09 00 00 00 00
F? ?L? ? V? ?版本 有音頻和視頻 9位
反正讀到這些就能知道格式了,知道格式之后,可以進(jìn)入拆包這部
demux (libavformat)
裸流一般是不用于傳輸?shù)?,所以大部分視頻流都會(huì)打成某種格式進(jìn)行傳輸和播放。就像送禮物需要找個(gè)盒子系個(gè)帶子一樣。這步就是拿來(lái)拆盒子的。因?yàn)槟愕腁VFormatContext里面已經(jīng)有東西(純直譯解釋就是音視頻格式上下文)就可以開(kāi)始解封裝了
此時(shí)能從你的?AVFormatContext 找到一共幾路流(AVStream),會(huì)由codec 的 codec_type字段標(biāo)識(shí)
AVMEDIA_TYPE_VIDEO 視頻
AVMEDIA_TYPE_AUDIO 音頻
由于一些版本進(jìn)化,ffmpeg 還引入了 codecpar 其實(shí)差不多,所以在看一些比較老的文章時(shí)候 是直接讀取codec 而新一點(diǎn)的則是 codecpar也會(huì)進(jìn)行處理。
anyway這會(huì)兒能取出來(lái)哪路是音頻哪路是視頻。等一會(huì)兒真的來(lái)了數(shù)據(jù)之后,就從這些stream取就完了
音頻/視頻?
上面已經(jīng)提到AVStream,這玩意就是包含了各路音頻 或者視頻 的編解碼格式信息,和一些附加信息。頭文件(比如AudioSequenceHeader之類的)到達(dá)時(shí),可以從Stream中取到信息。但是注意的是,標(biāo)記哪路音頻 哪路是視頻。
讀完Codec信息,會(huì)一個(gè)片段一個(gè)片段的來(lái)數(shù)據(jù)。能讀到就讀呀,先會(huì)存儲(chǔ)到AVPacket里 (但這個(gè)結(jié)構(gòu)體,并不是只有這個(gè)時(shí)候才會(huì)用到 2333)
解碼?(libavcodec)
有了以上這些信息,解碼的主要流程就是,先打開(kāi)一個(gè)解碼器? avcodec_open2 再拿來(lái)解碼? avcodec_decode_video2 最后都解碼完成再關(guān)上 avcodec_close。
注:要把大象拿出冰箱總共分幾步:把冰箱門(mén)打開(kāi),把大象拿出來(lái),再把冰箱門(mén)關(guān)上。差不多的意思。
此時(shí) 你的AVPacket應(yīng)是解到一個(gè)一個(gè)的AVFrame里。
當(dāng)然根據(jù)解碼標(biāo)準(zhǔn)不同,還有更細(xì)分的單元 (比如nal),這些ffmpeg的AVCodec 已經(jīng)幫忙實(shí)現(xiàn)了,可以不用管它。
處理?(libavfilter)
然后你就有些比較原始的數(shù)據(jù)了(比如YUV數(shù)據(jù))可以用?libavfilter 里面的一些方法做簡(jiǎn)單處理。不過(guò)想要搞基高級(jí)的處理,可以引入別的庫(kù),或者自己寫(xiě)(不得不說(shuō)這個(gè)真的牛批)。
其他常用庫(kù)包括 opencv(分析及處理) tenserfollow(大數(shù)據(jù)分析)等。至于用啥,自己看著辦比較好。
編碼
此時(shí)有了處理后的數(shù)據(jù),仍然這里要寫(xiě)兩種方式
調(diào)用(libavcodec)中的編碼器進(jìn)行編碼,比較簡(jiǎn)單,要把大象裝冰箱系列。
自己調(diào)用編碼器。以x264編碼器為例,嗯。。。記得裝x264庫(kù),以及弄清上百個(gè)參數(shù)的含義。再實(shí)現(xiàn)一遍libx264 →_→
mux(libavformat)
也沒(méi)什么可說(shuō)的,如同過(guò)年的時(shí)候某人送了我一盒西洋參。然后我換個(gè)包裝,正月十五又送人是一個(gè)道理的。此時(shí)再把他封起來(lái)就行了。
創(chuàng)建一個(gè)AVFormatContext 然后把AVStream掛上 avformat_new_stream
輸出
該是送禮的過(guò)程了,先打開(kāi)一個(gè)IO通道 avio_open 然后寫(xiě)頭avformat_write_header然后一個(gè)packet一個(gè)packet的寫(xiě)咯av_write_frame/av_interleaved_write_frame 區(qū)別和時(shí)間戳有那么一絲兒關(guān)系。后面再說(shuō)。
a方法的好處是,方便。b方法的好處是。。?!鷂→其實(shí)參數(shù)大部分都暴露了呀,沒(méi)什么特別好的,只是參數(shù)用的6的話,確實(shí)會(huì)產(chǎn)生更好的編碼效果。但是您真的有信心寫(xiě)的比那幾個(gè)預(yù)設(shè)的參數(shù)好么?
個(gè)人理解,如果貼近業(yè)務(wù),比如研究透了 英雄聯(lián)盟用什么參數(shù),絕地求生用什么參數(shù)。主播唱歌用什么參數(shù),查房又用什么。MAD用啥,MMD用啥。自己寫(xiě)編碼參數(shù)才是有意義的。然而大部分人連預(yù)設(shè)都是什么東西 要搞明白都得一段時(shí)間。所以還是老老實(shí)實(shí)寫(xiě)預(yù)設(shè)就挺好。
坑點(diǎn):(這里只能寫(xiě)現(xiàn)在已知的)
1. 時(shí)間戳:PTS(展現(xiàn)時(shí)間)不一定都正確的一個(gè)一個(gè)來(lái)。目前遇到的CDN還真有瞎(屏蔽臟字)的給的。調(diào)起來(lái)賊難受。也沒(méi)啥辦法
2. Gop大?。杭搓P(guān)鍵幀間隔,除了FPS、參考的幀數(shù)、分辨率等等參數(shù)之外,每個(gè)Gop多大也蠻重要的。不僅影響效果,也影響直播的首屏和延遲、點(diǎn)播的首屏?,F(xiàn)在基本是純憑經(jīng)驗(yàn)來(lái)吧。。
3. B幀處理 →_→:主要是點(diǎn)播轉(zhuǎn)直播,一個(gè)很惡心的問(wèn)題就是,B幀。正常的直播流是不應(yīng)該出現(xiàn)B幀的(增加延遲、首屏?xí)r間,畢竟是要前后兩個(gè)參考幀,還要等后一個(gè)參考幀數(shù)據(jù)到達(dá)播放器才能起播)。如果省去轉(zhuǎn)碼環(huán)節(jié) 直接轉(zhuǎn)封裝?;緵](méi)法處理。帶了轉(zhuǎn)碼環(huán)節(jié)。需要在編碼時(shí)設(shè)置不要B幀。
編了2400+字了,不想寫(xiě)了 細(xì)節(jié)下一篇吧(如果我有耐心寫(xiě)完的話)。。。
---------------------------------------
扣扣群:711929228 入群?jiǎn)栴}:例舉mysql的索引方式。。請(qǐng)谷歌或百度 (基本答得出來(lái)btree和hash 就行了)長(zhǎng)期被噴進(jìn)群?jiǎn)栴}太難的我,最近換了個(gè)簡(jiǎn)單的。。。基本倆月?lián)Q一次,不會(huì)挨噴了吧??
上期進(jìn)群?jiǎn)栴}及答案:
請(qǐng)例舉三種熵編碼算法
Huffman 大二學(xué)的,gzip在用的
cabac H264編碼標(biāo)準(zhǔn)中的一種熵編碼算法。
cavlc?H264編碼標(biāo)準(zhǔn)中的一種熵編碼算法。
其他只要是就行,比如算數(shù)編碼啥的。。