<small id="6kayo"><wbr id="6kayo"></wbr></small>
<center id="6kayo"></center>
<div id="6kayo"><center id="6kayo"></center></div>
<wbr id="6kayo"></wbr>

全國服務熱線:0551-64931480

04
18-12

直播視頻秒開背后的技術與優化經驗

李雨來 748984 0

??使用常見的視頻直播服務器,比如Nginx-RTMP做一個簡單的Demo環境。我們用OBS往Nginx-RTMP上推流,隨便找一個播放器播放。一般情況下,我們會看到一個黑屏,然后過一會之后,它才會出現圖像。我們對比一下,如果我們看手機直播,像陌陌直播,映客,我們點一下播放按紐之后,一秒鐘之內視頻直接就出來了。今天我們要講的內容就是這個差別是怎么形成的,背后的原理是什么。出現黑屏的原因很簡單,就是解碼器沒有得到能解碼出視頻圖像的數據,那么導致這個問題的原因就很容易定位了:

??比較搞笑一點的說法就是你家的網絡比較慢;

??視頻直播服務器沒有打開關鍵幀緩沖。

??那么就這些了嗎?我想對于這個問題來說確實是這樣。為了探究其中的原委,接下來我們需要往下去挖掘一下視頻到底是怎么播放的。

??視頻是如何播放的

??視頻要播放它肯定是有視頻數據,把視頻數據放到編碼器,然后編碼器把這個視頻數據解碼出來,解成圖片,然后播放到顯示器上,這是一個基本的播放流程。一般來講,大家現在主流的用H.264編碼。對于H.264編碼來說,我們會有三個不同的幀,所謂幀是什么呢?就是你看到的每一個圖像。我們看到動態的視頻,大家知道電影最開始用膠片拍的時候,每秒是25幀,是每秒25個圖片在切換。對于H.264來講,我們常見的有I幀,P幀,和B幀。

??1.I幀,I-Frame也有人會叫Inter Frame,那么它的意義是什么?

??(1)它是一個自描述幀,你可以理解為它就類似一個jpg圖片,它里頭所有的數據,你解出來之后,它就是一整張圖片。

??(2)無其他幀引用,它不需要去做前置和后置的引用。

??(3)它壓縮比是最小的,因為它要包括整個圖片所有的數據在里頭。

??2.P幀,P-Frame也就是說預測幀,它的預測幀是怎么回事呢?大家有沒有用過版本管理軟件,比如git或SVN,這樣可能大家會比較好理解,P幀就是保留變的部分,不變的部分你去上一個或者幾個幀里面找就行。P幀只是負責向前引用,也就是任何一個P幀,它只看它往前的這些幀的數據。P幀的好處是什么呢?因為它只存一些變化信息,所以它大概的壓縮比是I幀的50%。這個數據哪來的?大家可以去翻一下維基百科,那里會有一些介紹。

??3.B幀,B-Frame,前后雙向引用預測。

??B幀比較特別,它要引用前面P幀某一部分的圖像數據同時B幀后面的數據也會引用,這個是B幀的特點,它要引用前面的數據,也要引用后面的數據。那么它的優勢就是壓縮比比P幀還大,大概是I幀的25%,也就是我們B幀用的特別多的話,它會把視頻的大小降的比較低,因為它的壓縮比更大一些。

??I幀,B幀,P幀它是怎么組成一個視頻流呢?我們管這個東西叫Group Of Picture,簡稱叫GoP。

??視頻解碼器,看到GoP它是怎么放呢?那很簡單,編碼器會有一個緩沖,然后它會保留從I幀開始,當然現在說是I幀,其實這個I幀還有個特殊的類型。從I幀開始,他會把數據緩存到解碼器的Buffer里,當他遇到下一個P幀,或者再下一個B幀的時候,它會從它Buffer里找到它之前引用的那個幀,然后把這個數據解出來,最終播放到顯示器上。那么緩沖區開始的第一個幀肯定是I幀,這個毋庸置疑。另外還有一個比較特別的點,B幀和P幀并不會只引用當前GoP里的幀,他可能會往前去引用上一個GoP中的幀。既然它有這么一個特性的話,我們什么時候去清空這個緩沖區呢?這里就要介紹一個新的概念,叫IDR幀。

??IDR幀

??IDR幀是I幀,但I幀并不一定是IDR幀,所謂IDR幀是什么?它就是拿到這個幀之后,播放器可以直接從這個幀開始往后播放,它保證后面的P幀和B幀的引用不會跨越這個IDR幀,那么看到IDR幀,編碼器就可以把當前的Buffer清空,從當前這IDR幀開始解碼往Buffer里邊放,后續幀就可以從Buffer里的數據引用,然后解碼,也就是說編碼器可以從任何一個IDR幀開始解碼。大家可以聯想到,當我播放一個視頻文件的時候,我可以拖動,但是我拖動的任何一個點,它肯定是一個IDR幀,當然它也是I幀,但是并不一定說每一個I幀我都能讓它作為一個拖動的點。

??IDR幀有時也有它不太學術的叫法:關鍵幀。在做編解碼程序的時候,我們可能會看到FFmpeg的數據結構里會標著PTS和DTS,那么PTS和DTS是什么呢?

??PTS和DTS是什么

?

??PTS,Presentation Time Stamp也就說這個幀什么時候會放在顯示器上;DTS就是Decode Time Stamp,就是說這個幀什么時候被放在編碼器去解。那么如果全是I幀和P幀,PTS和DTS都是單調遞增的,那么如果我們有B幀,會出現什么情況?因為大家都知道,對于B幀來講,它會引用前面的幀和后面的幀。

??我們看這個例子,就是當B幀進來的時候,因為它要引用后面的P幀,也要引用前面的I幀,可以看到DTS的順序,一三四二,然后PTS順序,一二三四。B幀它會根據它編碼時候的特性,它會自動的把它的DTS時間戳往后挪,把它引用的幀先放到前面去,等它引用的幀解完了,數據解完了之后,才會把B幀去解,否則的話,我先把B幀放進去,它引用后面的P幀,P幀的數據還沒有,B幀解不出來。所以說這點上給大家講一下,B幀,P幀,I幀它們整個放在一個視頻流里面,它的解碼順序和編碼順序,當然后續的話,我們可能會根據這個有一些開放性的思考。

??為什么直播會等待

??對于直播來講,它是一個流,它不像點播,大家都從0秒開始,任何一個視頻文件,0秒第一個幀肯定都是關鍵幀。那么對于直播來講,我是一個隨機的時間點接到這個視頻流進行播放,那么我接入的這個時間點的幀有可能拿到的第一個幀的數據是I幀,也有可能是B幀,也有可能是P幀。這是一個隨機的。在這種情況下,我們大概率會出現一個黑屏的狀態。因為我拿到的是個P幀,對于P幀來講,解碼器面那個Buffer是空的,它不知道這個P幀如何進行解碼,所以它只能丟棄這個幀。

??對于直播來講,我一秒鐘的幀數是固定的,只能等到我下一個關鍵幀到來的時候,我才能開始去播放。當然正好趕巧了的話,接入那瞬間得到的數據正好是個I幀。就可以達到秒開的效果。

??關鍵幀緩沖如何工作

??其實是在cache服務器上,它會去預先解一下這個幀,然后去看它到底是個I幀,還是個B幀,還是個P幀,當它發現是I幀的時候,它會放在它的程序的內存里頭,當你每一次打開這個視頻流的時候,cache服務器會把內存中的I幀發送給客戶端比如當前播放到了P幀,那我把P幀前面的I幀和P幀全波放到cache的內存里,然后當客戶端接入之后先把內存里的數據發送給客戶端解碼器,然后再從這個B幀往后給。對于這個解碼器來講,它很舒服,它接到第一個數據流的第一個包肯定是I幀,那么它就可以直接播放了。

??如何去做到秒開?

??沒有什么好的方法,任何人做這種事時候都是一個笨的方法,就是去看文檔,沒有什么捷徑。大家可以翻閱FLV視頻文件格式文檔,它會告訴你package里頭,它任何一個Video里的package有一個Video TagHeader,對它是有一個Frame Type,Frame Type如果把它解出來,它是1的時候,它管這個叫key Frame,咱們看后面這個AVC,a seekable Frame你可以理解為它是個IDR幀,它并不一定就是I幀。

??幾個問題

??1.開放性的解決問題,GoP Cache是從當前的這個GoP幀開還是從上一個GoP開始

??這個問題比較有意思的是我從上一個GoP放的話,我拿過來的肯定是直接可以放了。因為有時我也預見過一些比較特殊的編碼,會導致我從當前這個GoP的第一個I幀拿播放器放出來,我這樣可能會提高編碼器的兼容性,但是它會有一個問題,就是如果GoP開的特別大的話,那么我的延時自然而然就會上去。因為我上一個GoP如果是十秒,等于說我拿的是十秒之前的數據,也就是你看到的是10秒之前他說的話,他做得表情,他做的動作。那么我從當前這個GoP開始,它肯定是有一定的延遲,但是不會大到超過你整個GoP。對于視頻直播來講,我們GoP size多少合適,換一句話講如果GoP size設成0,所有都是I幀,不存在任何GoP cache問題,但是碼率來講會很高,因為所有的都是I幀,我們知道它壓縮比會比較低,那么反過來,就是我需要設一個GoP的Size是多少呢?

??2.視頻直播的GoP Size設置成多少合適

??一般來講,對于手機直播,一到兩秒可能是比較合適的,因為它本身的GoP時間也不會很長,我這邊緩沖,一旦出現問題大概一到兩秒這個視頻也能出來。有一個不太好的地方就是它碼率會稍微高一些,也就說同樣的東西,如果我把GoP改成十秒,我可能是500K,但是我改成一秒,有可能變成一個六七百K的樣子,這個還是跟編碼有關系,具體的比例是多少,可能跟實際相關。

??另外如果是點播的話,不關心首屏打開時間,只要是客戶端下來速度快,CDN給力,那么我可能要求更小的范圍。告訴大家一個實踐過程中得出的結果,大家用過OBS?比如說做主播的話,大家用OBS會比較多,OBS它有一個問題就是它默認的話,如果你不調它的特性,GoP就是10秒,10秒的意思就是說GoP size。如果比較點背的話,看的是10秒之前的,如果是比較大的話,它的碼率,碼流的大小會小點,但是延遲會稍微高一些,CDN開了幾個cache,有些情況下,我們也可以做些轉碼,強行把它的GoP size壓小,整個CDN層面上加一個轉碼的話,它可能會增高這個延遲,這塊一個開放性問題,大家可以根據自己的場景去思考,這個GoP Size配成多大比較合適。

??3.你在視頻直播中到底用不用B幀

??我有時候在搜相關的資料,也有做直播的不用B幀,所以這一塊我并沒有什么結論,就是說給大家一個點,讓大家去想一想。鑒于B幀之前看的DTS和PTS的PPT,也知道B幀在解碼的時候,它是要打亂每一個幀傳入解碼器的順序,如果丟包或者一些特殊情況,它可能會影響解碼器的運行的特點。

??一個數學故事

??我不知道有多少人聽說過這個事,就是1943年以前,二戰的時候,因為英國被德國打的都已經找不著北了,他希望美國在后面支持英國,然后去做一些物資上的支持,那么就會有很多的商船,運輸船把它的物資源源不斷的從美國送到英國,德國人反制方式是什么?它的狼群潛艇在大西洋里逛。對于軍事學家來講,他們可能想不出來一些什么好的辦法,他們就請來一些數學家問我這個商船怎么開比較合適,能保證一個是我的損失最小,另外一個我物資運送最大,碰到狼群的次數越低。這些數學家根據概率統計的概率論,然后得出一個結論,就是一定數量的船隊編隊規模越小,編次流越多與敵人相遇的概率就越大,換句話來講,就是我這個船隊肯定是攢足了,比如說我原來有一百艘船的貨運量,那么我每一次發一艘船過去,那么我可能遇到狼群的概率會大一些,但是我把這一百艘船變成一個編隊,然后我把我的護航編隊做到足夠好,我把我這一群送過去,我碰到的狼群概率很低的情況下,我可能效率更高一些。

??數據包與網絡抖動之間的斗爭

??我們從這個數學故事發散去考慮一個問題,我們把視頻的數據保管好,運維的數據保管好,當成我們的運輸艦,把網絡走動,丟包,我們想成是一個狼群,就是德國的潛艇在整個大西洋上跑。我們就可以根據這個數學結論去考慮一個特殊的點,我們的發包節奏是什么樣的。

??因為我發一個包,比如說我發出一個數據包過去,你可以理解為,我從美國發了一批貨運船,帶了一行護行艦隊去往英國,那么我們到底是有數據就往外發,還是我們攢一波數據之后往外發?這個就我剛才說的,你發包頻率應該是有講究的,看怎么去發比較合適。

??另外,可不可以換一種思路,使用類似TCP慢起動這樣的算法,我最開始為了保證首屏時間,我以最快的發包速率往上發,等我發到一定的程度的時候,換成慢包率發送,把時間拉長一點,拉倒一個可以接受的范圍,然后逐漸的去調整這個東西,當然這可能是比較傳統的,樸素的方式。最終的效果呢大家還得自己去根據這個特性自己想,這也是一個開放性的問題。

評論列表(0)
暫無評論
亚洲欧美日韩国产另类丝瓜|91偷拍裸体一区二区三区|囯产精品一区二区三区AV做线|午夜精品久久久久久久99热 亚洲成色999久久网站|无码日韩精品一区久久|精品国产一区二区三区无码|99人人超碰国产精品最新 国产丝袜无码一区二区三区 日本高清二区视频久二区
<small id="6kayo"><wbr id="6kayo"></wbr></small>
<center id="6kayo"></center>
<div id="6kayo"><center id="6kayo"></center></div>
<wbr id="6kayo"></wbr>