1. 程式人生 > >播放器技術分享(4):首開時間

播放器技術分享(4):首開時間

搞音視訊開發好些年,分享過許多部落格文章,比如:前幾年釋出的《FFmpeg Tips》系列,《Android 音訊開發》系列,《直播疑難雜症排查》系列等等。最近想把多年來開發和優化播放器的經驗也分享出來,希望能幫助到音視訊領域的初學者。第一期文章要推出的內容主要涉及到播放器比較核心的幾個技術點,大概的目錄如下:

1.  播放器技術分享(1):架構設計

2. 播放器技術分享(2):緩衝區管理

3. 播放器技術分享(3):音畫同步

4. 播放器技術分享(4):首開時間

5. 播放器技術分享(5):延時優化

本篇是系列文章的第四篇,主要聊一聊如何優化播放器的首開時間。

1 首開時間的定義

image.png

首開時間:從點選播放到第一幀畫面顯示出來的耗時。通常大家說的 “首屏秒開” 指的就是播放器的“首開時間”在 1s 以內。

首開速度是使用者最簡單、最直接的體驗,所以通常是播放器開發中優化的重點。

下面是一個典型的首開速度和使用者感受的關係表:

image.png

2 首開時間的影響因子

要優化播放器的首開時間,我們得先了解一下影響播放器首開時間的因素有哪些,下圖簡單展示了播放器向伺服器申請播放一個視訊流的全過程。

image.png

想優化播放器的首開時間,首先關注一下播放流程中的每個環節,如圖所示,可能的優化點列表如下:

  1. 申請資源的播放 URL 地址的時機優化 -> 爭取在使用者點選播放之前拿到 URL

  2. DNS 解析優化 -> 提前完成 DNS 解析,並快取結果

  3. 伺服器的連線和資料傳輸速度優化 -> 主要是伺服器節點與播放器之間的網路傳輸優化

  4. 視訊流的媒體資訊解析優化 -> 主要是解析提取演算法的優化

  5. 解碼和渲染策略優化 -> GOP 快取,確保首幀為關鍵幀解碼渲染

  6. 其他優化手段 -> 測速選線、解碼演算法效能等

在這個過程中,每一個環節都有一些影響因子會決定播放器的首開時間,我們下面詳細展開優化思路。

3 首開優化方法

3.1 優化 URL 的獲取時機

image.png

如圖是一個播放列表,每個視訊都會對應一個資源的 URL 播放地址,如果在使用者點選視訊後,APP 再去後臺業務伺服器去申請這個 URL 播放地址,無疑增加了一次 HTTP 請求和應答的耗時,特別是網路不穩定的時候,耗時更加明顯。

因此,這是一個可以在 APP 層進行的優化點:在拉取視訊播放列表的時候,“同時” 把視訊的 URL 播放地址也拉取下來,在使用者點選視訊後無需再向伺服器申請播放地址,即可立即開始播放了。

3.2 優化 DNS 解析時間

視訊資源的 URL 地址,往往是包含域名的,比如:

http://jhuster.com/video/movie.mp4

播放器在播放前,需要先進行 DNS 解析,把 jhuster.com 這個域名解析為一臺伺服器的 IP 地址,然後才能通過 TCP 連線上去,傳送資源請求。

我們在 17CE 網站上簡單測測這個域名解析的時間:

image.png

可以看到,平均 DNS 解析時間在 673ms 左右,但是在很多地區(比如:佛山市電信,北京市電信)解析時間都超過 2s 了,可想而知,在這些地區 DNS 解析緩慢對播放器首開時間是致命的傷害。

為了確保所有地區的視訊播放不過於受 DNS 解析速度的影響,除了為視訊資源的域名購買付費的專業 DNS 解析服務外,播放器層面也可以針對性地做一些優化,如下圖所示:

image.png

播放器內部新增一個 DNS 結果快取模組

  1. 在非同步執行緒定時執行 DNS 解析,並把 “域名 & IP 表” 快取在記憶體中

  2. 視訊播放時,直接查表,取出域名對應的 IP 地址,送入播放器

注意事項:

  1. 一個 APP 的資源域名個數是收斂的,不是無限個,所以可以在 APP 啟動的時候,送入播放器提前去完成 DNS 解析和快取

  2. 未提前配置的域名,在第一次解析的時候,依然會首開慢,但該域名第二次即可從本地快取中取了

  3. 需要注意快取的 IP 地址的重新整理:

    • DNS 解析有一個 TTL 超時時間,到期前要記得重新解析重新整理

    • 監測手機網路切換事件,比如:WiFi 切換到 4G 後,需要清空快取

舉個例子:

DNS Cache Map:  <jhuster, 185.199.108.153:80>

如果要播放 URL:http://jhuster.com/video/movie.mp4

可直接替換為播放: http://185.199.108.153/video/moive.mp4

坑在哪 ?

當我們真的用 ip 地址去播放的時候,會發現伺服器會拒絕訪問,例如報如下錯誤:

image.png

原因:視訊資源的 CDN 服務商需要知道是 “誰” 在申請這個視訊資源 -> 為了計量和計費,服務商的判斷訪問依據是“域名”,所以直接使用 IP 訪問會遇到上述問題。

怎麼解決 ?

  1. HTTP  協議:有個 HOST 欄位,記錄了伺服器的域名

  2. RTMP 協議:有個 tcUrl 引數,記錄了完整的播放器地址(含 伺服器的域名)

其實 CDN 服務商並不是從 URL 取的域名,而是從 HTTP/RTMP 協議中的上述欄位中 “提取” 的域名,因此,我們需要改造播放器底層的 HTTP/RTMP 程式碼模組,提供一個介面,可以把 URL 中原始的域名填入到上述協議欄位中即可。

3.3 優化伺服器連線和資料傳輸時間

播放器通過 DNS 解析拿到了伺服器的 IP 地址,下一步就是通過 TCP 連線伺服器,然後傳送請求讀取資料了。在這個過程中,與伺服器的連線速度以及資料的傳輸時間非常重要,直接影響著首開體驗。

這個因素並不是在播放器層面可以執行的優化,因此就簡單提一下,優化的關鍵因素在於伺服器的負載、CDN 的節點分佈和頻寬情況了。這也是為什麼一般的 APP 公司會採購和使用 CDN 服務的原因了。

image.png

3.4 優化媒體資訊的讀取策略

視訊的媒體資訊裡都有啥 ?

  1. 是否包含:音訊、視訊

  2. 音訊、視訊的編碼格式,如 H.264,AAC 等

  3. 視訊的資訊,如 解析度、幀率、位元速率

  4. 音訊的資訊,如 取樣率、位寬、通道數

  5. 碼流的總時長

  6. 其他附加資訊,如 作者、日期等

可見,媒體資訊對於初始化播放器還是非常重要的。不同的音視訊封裝格式,媒體資訊存放的位置也不太一樣,像 flv 格式,媒體資訊往往直接存放在開頭,因此是比較容易第一時間讀取到的。而 mp4 格式,常常會遇到 moov 在尾部的情況,這種是播放器優化的重點,如圖所示:

image.png

對於這種把媒體資訊存放到了尾部的 mp4 檔案,預設的播放器需要把整個 mp4 全部下載下來才能拿到媒體資訊,對首開是極其不友好的。

如何優化呢 ?—— 雙 IO 技術

image.png

如圖所示,對於 moov 媒體資訊在尾部的 mp4 檔案,播放器讀取一定資料後,如果判斷 moov 在尾部,則可以暫停這個執行緒,同時啟動第二執行緒通過 http range 欄位讀取尾部的 moov,從而拿到關鍵的媒體資訊,這樣的技術策略的好處是:

  1. 無需下載整個 mp4 即可播放 moov 在尾部的視訊

  2. 第一個 IO 已下載的部分可繼續利用,不用丟棄

3.5 優化媒體資訊的解析時間

媒體資訊解析的工作量在哪 ?

  1. 判斷碼流的封裝格式,比如 mp4,flv,m3u8 等等

  2. 根據封裝格式的協議約定,提取資料中的媒體資訊

為了提高對非標準碼流的相容性,ffmpeg 使用了一套非常複雜的解析策略,即使從碼流中已經提取到了 metadata,依然會做各種 double check,比如,多次 try_decode_frame 測試是否真的可以成功解碼資料,從而導致底層基於 ffmpeg 的播放器,首開速度會在這裡降下來。

如何優化呢 ?如果是基於 ffmpeg 核心的播放器,那麼常用的手段如下:

  1. 減小 probesize

  2. 減小 analyzeduration

  3. 預設碼流的音視訊格式

3.6 優化首幀解碼和渲染

我們知道,編碼後的視訊幀是分 I、B、P 幀的,I 幀是關鍵幀,可獨立解碼出影象;B/P 幀分別是前向預測幀/雙向參考幀,是需要參考 I 幀或前後幀才能解碼出影象的。

因此,為了儘快解碼出首幀畫面,需要確保送入編碼器的首幀即是 I 幀。


image.png

如圖所示,在直播場景下,如果觀眾在 C 時間點拉流,則正好可以拉取到一個 I 幀,迅速完成解碼播放,實現秒開。但是如果不巧,正好在 A 時間點或者 B 時間點拉流,則會導致無法解碼,一直要等到下一個 I 幀才能完成解碼渲染。

因此,一般的直播雲廠商,都會在服務端快取一個 GOP 的資料,無論任何時候,播放器申請播放,都會首先下發這樣一個以 I 幀開頭的 GOP 資料,從而加快了播放器的解碼和首開。

對於播放器而言,需要注意的時候,當第一幀還沒有渲染之前,先不要主動緩衝,而是儘快先渲染首幀。

4 總結

當然,還有很多其他的播放器首開時間的優化策略,測速選線、解碼演算法效能等,用的不是很廣泛,這裡就不展開介紹了。關於播放器的首開時間優化,就分享這麼多了,如有疑問的小夥伴歡迎來信 [email protected] 交流。另外,也歡迎大家關注我的新浪微博 @盧_俊 或者 微信公眾號 @Jhuster 獲取最新的文章和資訊。

weixin_jhuster.jpg