簡(jiǎn)述追幀的原理和追幀在直播同傳的中的使用
關(guān)于直播和同傳經(jīng)常能看到一些源于想象的傳言,類似:同傳man會(huì)和主播單獨(dú)連麥,所以會(huì)比一般觀眾更早看到直播;主播在直播中會(huì)開延遲推流,所以彈幕會(huì)需要10多秒才會(huì)上屏。類似傳言本質(zhì)上來源于對(duì)直播原理的不了解,所以這里我想簡(jiǎn)單的敘述下直播的一些基本機(jī)制,以及利用了這些機(jī)制的追幀腳本能實(shí)現(xiàn)的效果。
因?yàn)槭呛?jiǎn)述所以專欄完全根據(jù)我個(gè)人的記憶進(jìn)行寫作,不保證完全準(zhǔn)確。
直播系統(tǒng)
無關(guān)乎具體的平臺(tái),一個(gè)直播系統(tǒng)根本上就是要滿足這么一個(gè)需求:利用計(jì)算機(jī)網(wǎng)絡(luò),將實(shí)時(shí)生成的音視頻流從一個(gè)人分發(fā)給許多人。而這個(gè)需求具體來說至少包含了兩個(gè)問題,第一是如果讓一個(gè)實(shí)時(shí)生成的音視頻流能像視頻文件一樣,讓包括瀏覽器在內(nèi)的客戶端進(jìn)行實(shí)時(shí)下載。第二是如何應(yīng)對(duì)互聯(lián)網(wǎng)連接中的丟包延遲等不穩(wěn)定因素。
分發(fā)實(shí)時(shí)的音視頻流
目前B站使用了兩套推流協(xié)議,一套是HTTP-FLV,另一套是HLS,來實(shí)現(xiàn)直播的推流。
HTTP-FLV大致上可以理解為服務(wù)器虛擬了一個(gè)flv的視頻文件,而這個(gè)flv里的內(nèi)容并不是事先保存的視頻,而是直播的視頻流。服務(wù)器把接收到的直播推流按flv格式實(shí)時(shí)封裝,再按照直播流生成的速度向?yàn)g覽器發(fā)送flv“文件”,而瀏覽器也按照相同的速度播放這個(gè)“文件”,這樣一來,瀏覽器就能像播放單個(gè)flv視頻文件一樣播放被包裝成flv視頻的直播數(shù)據(jù)。HTTP-FLV最大的優(yōu)勢(shì)就在于“實(shí)時(shí)”,只要服務(wù)器收到了一幀數(shù)據(jù),理論上就可以立刻把這一幀數(shù)據(jù)封裝進(jìn)flv發(fā)送出去。
Bilibili早年從Flash時(shí)代就一直使用的FLV格式進(jìn)行視頻播放。后來Flash逐漸廢棄,網(wǎng)頁逐漸轉(zhuǎn)向HTML5的時(shí)候,Bilibili推出了flv.js,實(shí)現(xiàn)了HTML5的FLV播放。不過Bilibili畢竟不是一個(gè)技術(shù)導(dǎo)向平臺(tái),現(xiàn)在也在逐漸轉(zhuǎn)向YouTube等使用的DASH和HLS。
HLS是由反Flash先鋒蘋果提出的一套協(xié)議。HLS的原理就是服務(wù)器收到直播流之后,先在服務(wù)器上保存很多很短的視頻片段,然后把這些視頻片段的網(wǎng)址放進(jìn)一個(gè)m3u8的文本文件里。瀏覽器則反復(fù)的獲取最新的m3u8的文本文件,然后根據(jù)m3u8中的網(wǎng)址下載新的片段,再按順序進(jìn)行播放。HLS因?yàn)閷⒅辈ヌ崆霸诜?wù)器上分割成了大量的視頻片段,所以相對(duì)HTTP-FLV來說更穩(wěn)定一些,但是因?yàn)樾枰彺嫫卧俜职l(fā),延遲會(huì)明顯變高。
B站主要使用以fMp4為主的HLS,可以實(shí)現(xiàn)每個(gè)分片長(zhǎng)度在1秒。但播放器必須下載完一個(gè)分片才能播放(而HTTP-FLV可以看作是逐幀下載),在小樣本測(cè)試中,原畫的HLS-fMp4延遲仍明顯高于二壓的HTTP-FLV。實(shí)際情況下,可以通過打開兩個(gè)瀏覽器標(biāo)簽,分別啟用/禁用“強(qiáng)制flv+avc”選項(xiàng),切換一次畫質(zhì)后比較延遲。


(秒數(shù)是我個(gè)人目測(cè)的,不是實(shí)際測(cè)量,僅提供一個(gè)量級(jí)的參考)
對(duì)于同傳追幀的應(yīng)用場(chǎng)景來說,HTTP-FLV是一套足夠穩(wěn)定的協(xié)議,所以應(yīng)當(dāng)盡可能的選取HTTP-FLV的推流,并避免使用二壓的推流。
應(yīng)對(duì)網(wǎng)絡(luò)的丟包延遲
通過互聯(lián)網(wǎng)進(jìn)行傳輸會(huì)不可避免地出現(xiàn)網(wǎng)絡(luò)的丟包延遲等不穩(wěn)定因素,雖然不穩(wěn)定是偶爾的,但是一個(gè)合格的直播系統(tǒng)必須予以考慮。對(duì)于網(wǎng)上會(huì)議、語音連麥這種高度強(qiáng)調(diào)實(shí)時(shí)性的場(chǎng)景,解決方案就是降低音畫質(zhì),以及部分跳過卡頓的部分的音視頻。而對(duì)于視頻網(wǎng)站的直播,則可以選擇用數(shù)秒的緩沖延遲來保證視頻的質(zhì)量和流暢。Bilibili、Youtube在內(nèi)的直播平臺(tái),都可以從右鍵打開統(tǒng)計(jì)菜單,查看當(dāng)前的緩沖時(shí)間。
換言之,當(dāng)播放器接收到直播的數(shù)據(jù)的時(shí)候,并不會(huì)立刻播放這部分?jǐn)?shù)據(jù),而是會(huì)將輸入放入直播的緩沖里,再進(jìn)行播放。這樣的好處就是,即便有網(wǎng)絡(luò)波動(dòng),導(dǎo)致2-3秒沒收到數(shù)據(jù),播放器也不會(huì)出現(xiàn)卡頓;等網(wǎng)絡(luò)波動(dòng)消失,播放器就可以從服務(wù)器拿到這期間的數(shù)據(jù),補(bǔ)回消耗的緩沖長(zhǎng)度,以應(yīng)對(duì)下一次的網(wǎng)絡(luò)波動(dòng)。
多一秒緩沖,就能多應(yīng)對(duì)一秒的網(wǎng)絡(luò)波動(dòng),但相應(yīng)的也就多了一秒的觀看延遲。Bilibili網(wǎng)頁端的播放器會(huì)緩沖4-6秒左右的直播,但事實(shí)上大部分情況只要有1秒左右的緩沖就可以保證網(wǎng)頁端的流暢播放。所以讓播放器提前播放出一部分緩沖的直播,削減緩沖的長(zhǎng)度,就可以明顯減少因?yàn)楸镜夭シ牌骶彌_帶來的延遲。

具體來說,就是追幀腳本可以預(yù)設(shè)一個(gè)目標(biāo)的緩沖長(zhǎng)度,當(dāng)播放器的緩沖長(zhǎng)度大于目標(biāo)長(zhǎng)度時(shí),就提高播放器的播放速度,這樣播放比直播快,播放器的緩沖就會(huì)不斷被消耗,緩沖帶來的延遲也會(huì)不斷減少,直至播放器的緩沖長(zhǎng)度達(dá)到目標(biāo)長(zhǎng)度。
從追幀的視角來看直播延遲
當(dāng)開啟了緩沖的追幀,并使用HTTP-FLV的原畫推流時(shí)(非二壓“原畫”/HEVC),實(shí)際就足以實(shí)現(xiàn)~1秒級(jí)的延遲。評(píng)估總延遲的方式很簡(jiǎn)單:發(fā)送一條彈幕,然后估測(cè)這條彈幕出現(xiàn)在直播畫面上的時(shí)間。這一過程的延遲包括了:1. 發(fā)送彈幕到服務(wù)器的延遲,2. 服務(wù)器到主播彈幕姬的延遲,3. 主播推流的總延遲(編碼推流至服務(wù)器,服務(wù)器推流到播放器,播放器緩沖)。當(dāng)采用了合適的追幀時(shí),完全可以達(dá)到發(fā)送的彈幕幾乎實(shí)時(shí)上屏的效果。
于是我們就可以從純技術(shù)的角度來回答,為什么“同傳man不是和主播單獨(dú)連麥”:因?yàn)殚_啟了追幀就已經(jīng)是實(shí)時(shí)的音視頻了,所謂的單獨(dú)連麥并不會(huì)明顯減少延遲。同傳追幀的核心是開啟了追幀后和其他觀眾的延遲差距,而無關(guān)乎和主播的絕對(duì)延遲。

一個(gè)常見的疑惑是為什么同傳的彈幕會(huì)比主播的語音先出現(xiàn)。一種帶有節(jié)目效果的解釋是主播是照著同傳的彈幕念的。但是只要知道了直播中的延遲來源就不難理解。在開啟追幀并使用HTTP-FLV的原畫后,相對(duì)于一般的觀眾,同傳man可以同時(shí)減少推流(2-4秒)和緩沖(3-8秒)帶來的延遲。對(duì)于不長(zhǎng)的語句,同傳man完全可以在延遲差的時(shí)間內(nèi),聽完整句,并完成翻譯和發(fā)送彈幕。也正因?yàn)檠舆t的多少是推流+緩沖決定的,不同觀眾的延遲是各不相同的,所以同一條彈幕,可能在部分人看來比語音先出現(xiàn),但在其他人看來則是比語音晚出現(xiàn)。