短視頻秒播優化實踐(一)

短視頻迎合了人們時間碎片化下的精神娛樂需求,或者現在追求“短平快”的大環境,我也有點短視頻中毒,沒事經常光顧某幾個短視頻APP,以至於冷落了某頭條和某易新聞基本很少點開了,這些時間加起來holy bible估計都能讀好幾遍了。當然這是一篇技術文章,其他心理學,社會學問題,產品問題就不在這裏討論了,咱也沒那個水平。

言歸正傳,我們也推出了短視頻相關的產品。

在短視頻的體驗中,起播速度無疑是最影響體驗的指標之一,因爲短視頻很短,十幾秒到幾分鐘不等,如果一個十幾秒的視頻,加載時間都要3秒,肯定是一個很壞的體驗;所以在產品定義之初,起播速度就設定了控制在1秒左右,大部分在1秒內,也就是業內說的“秒播”,這需要對播放流程進行優化。艾瑪,終於繞到主題上了。

談具體的優化之前我們先看下一個短視頻播放的大概流程是怎樣的?

再通過拆解流程,找到可以優化的模塊或點,最終才能連成線,並給出優化方案。
在這裏插入圖片描述
如上圖所示,移動設備的播放器通過某個視頻url的域名,通過DNS服務請求到IP地址,通過這個IP地址與視頻服務器建立TCP連接,然後在連接之上建立http協議,最終請求到數據,給到播放器進行解析音視頻解碼顯示,用戶看到畫面聽到聲音,一個起播流程結束了。

爲了更好的發現可優化的地方,我們對上圖進行了拆解,結合實際情況給出了下邊這張圖
在這裏插入圖片描述

圖中藍色的部分是可以優化的,但由於實際情況是,flyme只在客戶端接入了內容,內容都是放在CP的服務器上的,雖然有優化空間但是flyme這邊優化不到,但在後邊我們也會介紹有哪些優化空間可以操作。這個是行業現狀,不過可以多接入幾家內容選擇豈不是更好。圖中灰色部分是不能優化的,在流程上沒有優化空間,而且這部分容易受到網絡情況的影響,所以我們後續提到的優化,是基於大多數normal的網絡情況的,雖然部分邏輯對極端網絡情況也適用,但是這不是我們討論的重點。圖中綠色的部分是可以優化並且在項目現實中可以實施的。

下面對這些項目逐一進行介紹。

一、Domain name: 域名解析
耗時原因:

DNS請求包會先發到本地DNS服務器,如果查不到,會遞歸到根域名服務器,這個過程是比較耗時的,當然如果你請求過了,或者期間有其他人請求過相同的域名,那域名服務器就會有緩存,再次請求的時候就很快了;但是一般緩存的週期很短,需要有人不停地請求才能保持更新,所以具有很大的不確定性。

解決方案:

1.注意請求使用的IP協議版本,做播放的肯定都繞不過ffmpeg,在ffmpeg裏爲了兼容性,DNS請求的IP協議版本設置爲AF_UNSPEC,這樣在請求的時候會先請求IPv6的地址,如果沒有再請求IPv4的地址,是很保險,但是在實際的項目中,沒有IPv6的地址,造成一直遞歸到根域名服務器也查不到IPv6地址,極大的浪費了時間,可以使用AF_INET指定請求IPv4地址,節省一半以上的時間,首次請求或緩存過期後請求,耗時大概在大幾十毫秒到100毫秒左右,可以通過監測getaddrinfo函數的耗時的到。
在這裏插入圖片描述

hints.ai_family = AF_INET;
getaddrinfo(hostname, portstr, &hints, &ai);

2.預置或預解析域名IP地址,100毫秒還是很大的一筆時間對於秒內播放來說,這個方案就是提前把域名解析出來,用的時候直接使用IP地址,但是這種方案有侷限性,可能適合特定的音視頻直播,對於短視頻播放地址比較多樣來說操作起來有一定難度,而且還存在CP切流和更換接入CP的情況,所以這個100毫秒目前只能先放在這裏了。

二、Socket cache:socket buffer
耗時原因:

TCP connection在客戶端的具體操作中基本都是通過socket實現的,在socket中有一個緩衝區的概念,發送端先把數據寫到緩衝區,接收端數據也是先經過緩衝區,再從緩衝區讀出,移動設備作爲接收端,接收端緩衝區設置的太小,影響效率,接收端緩衝區設置的太大,會短時間內吃掉帶寬,如果帶寬不夠會引起網絡傳輸問題,還會造成流量的浪費。這些都會影響首屏數據的及時送達。

解決方案:

根據實際情況調整接收端緩衝區大小,通過計算和測試數據得到一個比較合理的值。可以在ffmpeg的network和tcp裏進行調整,這是比較低層的修改了,爲了通用性可以擴展http/tcp的options並通過ffmpeg提供的AVDictionary機制在avformat API這一層進行透傳相關設置參數。
av_dict_set(&avdictionary, “param”, “value of param”);
setsockopt(fd, SOL_SOCKET, SO_RCVBUF,&len,sizeof(len));

三、Probe buffer
耗時原因:

在播放端,一開始並不知道要播放的視頻的相關信息,比如封裝格式,分辨率,音視頻編碼等信息,需要先讀一段數據進來,再對這段數據進行探測,得出相應的信息,而存放這段探測數據需要一個buffer。這個buffer設置的太小可能導致分析不出信息導致重新探測,設置的太大就會增加收流的時間從而影響了首屏的播放,太小太大都會引入延遲。

解決方案:

根據實際情況調整這個buffer,通過計算和測試數據得到一個比較合理的值。可以通過ffmpeg的AVFormatContext結構體的probesize和max_analy_duration把對buffer的限制透傳下去。可以通過觀察avformat_find_stream_info這個函數來評價探測耗時。
AVFormatContext->probesize = n;
AVFormatContext->max_analyze_duration = m*AV_TIME_BASE;

四、Probe list
耗時原因:

同樣是探測的流程,一開始播放端並不知道這段數據是什麼格式,需要根據自己支持的格式通過探測得出一個分數,然後依據這個分數給出相應的格式,類似於android的sniff,所以如果ffmpeg設置的支持的格式越多這個探測list就越長,相應的探測時間也就越長。而對於短視頻來說,CP的內容格式基本是確定的,基本都是MP4+H264/H265(不常見)+AAC。所以很多格式的探測是不必要的。

解決方案:

對於沒有用的格式在ffmpeg build config裏移除,只保留需要的格式,比如mp4,最大限度的減小probe list。可以通過觀察avformat_find_stream_info這個函數來評價探測耗時。
disable avi
disable asf
disalbe mkv
and so on…

五、Player buffer
耗時原因:

對於非直播類的播放器,業內的一般做法是都會在player內設計一個緩衝buffer,這是爲了播放流暢性和音視頻同步的需要,尤其是在網絡不穩定或較差的情況下,這個緩衝buffer顯得尤爲重要。一般這個緩衝buffer有按照幀數設置的,也有設置爲1-2秒的,也有設置爲3-5秒的,因爲一般的播放比如在線電影,電視劇考慮的是整個播放過程幾十分鐘,甚至幾個小時的體驗,在開始緩衝個幾秒是可以接受的,但是在短視頻的場景下這是不可接受的。

解決方案:

策略性的優化,保證視頻第一時間輸出,把緩衝機制移到首屏播放之後,當然這裏也要照顧到音頻,保證音視頻的同步,有些取捨要做。
這裏其實是很重要的一個環節,Android的nuplayer框架設計上受限於這些因素起播速度就遠達不到要求,又搞了個exoplayer,但是不做二次開發exoplayer還是不能滿足需求。這個需要根據自己的播放框架來做設計,我們使用的是自研的Normandie播放框架,該框架已經上線將近兩年,支持了多個音視頻的業務,這裏就不詳細展開了。

六、MP4 Size:分辨率/QP/I幀位置
耗時原因:

分辨率這個不難理解,如果視頻文件的分辨率很高,那它一幀的數據會很大,相應的傳輸時間就會變長。所以在內容產生的時候選擇合適的分辨率錄製或轉碼爲合適的分辨率也是爲播放端的負載在考慮,移動端720P左右足夠了對於個人秀之類的短視頻,內容聚合類的短視頻分辨率可以更低。QP指的是圖像質量,同一個分辨率的圖像可以有很多級的QP,它是跟編碼密切相關的,QP越高圖像質量越高碼率也越高,相應的傳輸時間也就越長。同樣,不是QP越高越好,對於不是不同場景快速切換的720P視頻,3M和5M碼率的區別不大。選擇合適的QP在畫面質量和傳輸上找到一個平衡。



I幀位置,指的是視頻I幀在視頻文件開頭的位置,播放器爲了防止花屏之類的問題出現,一般在開始播放或seek時都會找到第一個I幀進行解碼,一般視頻文件一秒有25-30幀,很明顯I幀放在第一幀和放在最後一幀對秒播是有影響的。
在這裏插入圖片描述

解決方案:

根據實際情況,在產品服務鏈條中選擇合適的分辨率/QP。
把I幀放在文件開頭第一幀的位置。

七、MP4 MOOV box position & Http re-connection
耗時原因:

如果在起播過程中發生了http re-connection耗時肯定會增加,而且http connection的耗時基本是不可優化的,所以要避免http re-connection的發生。但是mp4作爲主流的短視頻封裝格式,它的MOOV box在文件中的位置直接影響了會否發生http re-connection,直接點說就是MOOV box放在文件的後面也就是MDAT box後,會產生http-reconnection,引入延時。

解決方案:

1.在上傳mp4文件的時候把MOOV box放在前面
2.在mp4文件上傳到服務器之後,重新封裝,把MOOV box放到前面

如果是傳統音視頻出身的工程師應該很清楚MOOV box,這裏做下簡單的介紹。mp4是由很多box組成的,其中MOOV box裏存放的是音視頻編碼之類的對播放很重要的信息,先要拿到這些信息才能播放。所以MOOV box放在文件的前面通過一次http請求就可以直接讀取到,解析,繼續讀取音視頻數據播放。MOOV box放在文件的後邊,但是播放器不知道它放在後面,需要先發起一次http請求讀開頭部分數據,發現沒有MOOV box,它會seek到文件後邊位置,讀取MOOV box,讀完之後再seek到文件前邊位置,從開始位置讀取音視頻幀數據播放,每發生一次seek就重新發起一次http connetion請求。所以MOOV box放在後邊比放在前邊多了2次http connection,用時是放在前邊方案的3倍。下邊是兩個短視頻一個moov box放在了前邊,一個放在了後邊,放在了後邊的通過NmdPlayer的log可以都看到會發生re-connection,請求文件最後一段數據來獲取moov box。
在這裏插入圖片描述
在這裏插入圖片描述

八、Server/CDN
耗時原因:

CDN節點部署,路由策略
緩存還是拉流
都會對延時產生影響

解決方案:

server進行相關的優化。

九、TCP connection
耗時原因:

協議耗時,比如TCP的握手機制等,在穩定的網絡下耗時基本是固定的,在較差網絡下耗時會較長

解決方案:

CDN骨幹網絡的部署可以改善這種情況。

十、Http connection
耗時原因:

協議耗時,在穩定的網絡下耗時基本是固定的,在較差網絡下耗時會較長

解決方案:

CDN骨幹網絡的部署可以改善這種情況。

對於做技術的同學來說,並沒有多麼高深的東西,需要做的只是抓住問題的核心,把一個大問題拆解成一個個小問題,然後完成一個個小目標,最後水到渠成。其實很多事情都是這樣的,你就把它看成一個技術問題,把它拆解成一個個小問題,完成一個個小目標,比如先賺它1個億。

我們也完成了一個小目標,通過優化大多數的短視頻起播速度都落在1秒內,達到了業內的“秒播”水平。

One more thing…
追求體驗的極致,一直是我們追求的目標,而每個功能每個細節體驗的極致累加起來就是最終產品的極致。
1.通過上邊的分析,我們認爲還有至少100~200ms的優化空間。
2.另外我們下一步計劃用大數據來監控沒有落在1秒內的情況,根據數據分析報告推動對這種情況的優化。這是我們下一個小目標。

很早之前錄的一個視頻,在線播放分辨率960x720的短視頻,這算是比較高的分辨率了,以快手,抖音等爲代表的個人秀類差不多是這個分辨率,抖音可能低一些;以西瓜等爲代表的內容聚合類的,分辨率要更低些大多640x360或480P。

S70901-18153290
http://v.youku.com/v_show/id_XMzU0MTg3MzE0NA==.html

優化前(未解耦的框架android框架)

slow
http://v.youku.com/v_show/id_XMzU0MTg3NTU5Ng==.html

優化後(解耦的框架normandie+短視頻定製優化)

fast
http://v.youku.com/v_show/id_XMzU0MTg3NTE0NA==.html

原創作者:Walker.Xu,原文鏈接:https://segmentfault.com/a/1190000014405913
在這裏插入圖片描述
歡迎關注我的微信公衆號「碼農突圍」,分享Python、Java、大數據、機器學習、人工智能等技術,關注碼農技術提升•職場突圍•思維躍遷,20萬+碼農成長充電第一站,陪有夢想的你一起成長。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章