Categories
程式開發

騰訊課堂點播上雲客戶端實踐總結


一、課堂騰訊雲點播 HLS 播放

1. HLS 淺析

(1) HLS 協議

點播業務目前用的是 HLS 協議。 HLS協議全稱是 HTTP Live Streaming,它是一個由蘋果提出的基於HTTP的流媒體網絡傳輸協議。 HLS協議規定:

  • 視頻的封裝格式是TS;
  • 視頻編碼格式為​​H264,音頻編碼格式為​​MP3、AAC或者AC-3;
  • 除了TS視頻文件本身,還定義了用來控製播放的m3u8文件。

HLS的工作流程如下圖(來源蘋果官網)所示:

騰訊課堂點播上雲客戶端實踐總結 1

  • Server

    Server獲取媒體輸入流,Media編碼MPEG-4(H.264 video 和AAC audio),然後打包到MPEG-2 (MPEG-2 transport stream)的傳輸流中,傳輸流會經過Stream segmenter,MPEG-2傳輸流會被分散為小片段然後保存為一個或多個系列的.ts 格式的媒體文件。

  • Distribution

    Stream segmenter會創建一個索引文件,通常會包含這些媒體文件的一個列表,也能包含元數據,一般都是一個.m3u8的列表,列表元素會關聯一個URL 用於客戶端訪問,然後按序去請求這些URL。

  • Client

    Client主要接受Client客戶端請求並提供相關聯的資源給客戶端。

(2)HLS 的 index 文件

index 文件就是 m3u8 文本文件,如下圖(來源蘋果官網)所示。客戶端播放HLS視頻流的邏輯是先下載一級Index file,它裡面記錄了二級索引文件(Alternate-A、Alternate-B、Alternate-C)的地址,然後客戶端再去下載二級索引文件,二級索引文件中記錄了TS、dk 的下載地址,這樣客戶端就可以按順序下載TS、dk 文件並連續播放。

騰訊課堂點播上雲客戶端實踐總結 2

以企鵝輔導為例,一級 index(master_playlist.m3u8)文件如下圖所示:

騰訊課堂點播上雲客戶端實踐總結 3

  • #EXTM3U —表明該文件是一個m3u8播放列表文件,必須在第一行給出;
  • #EXT-X-VERSION:3 —播放列表文件的版本,現在主流版本是3;
  • #EXT-X-STREAM-INF —不同碼率的數據流 ;
  • PROGRAM-ID=0 —唯一標記;
  • BANDWIDTH=92166 —這個值是十進制整數代表每秒鐘的比特率,這個值必須是整個播放列表中碼率的峰值;
  • RESOLUTION=384×288 —視頻流的分辨率。

二級 index(對應任意一個清晰度)文件如下圖所示:

騰訊課堂點播上雲客戶端實踐總結 4

  • #EXT-X-KEY —媒體文件有可能要被加密,該標籤描述瞭如何解密媒體文件;
  • METHOD —包括NONE、AES-128、和SAMPLE-AES。如果該值是NONE或播放列表沒有定義該標籤,表示媒體段沒有被加密。如果設置了NONE,則其他屬性不會出現。其中AES-128表示媒體是由AES-128標準構造的的128bit的 key,和密碼塊鏈接(CBC)和PKCS7加密組成的,URI 參數必須出現在METHOD後面;
  • URI —描述瞭如何獲取key文件;
  • IV —IV可以不存在,如果沒有IV則使用序列號作為IV進行編解碼,將序列號的高位賦到16字節的buffer中,左邊補0,如果有IV,則將該值作為16字節的16進制數;
  • #EXT-X-MEDIA-SEQUENCE —m3u8播放列表中第一個出現的媒體段的序列號;
  • #EXT-X-TARGETDURATION —該標籤描述了媒體段的最大時長,EXTINF後面的實際媒體段時長不能超過這個標籤描述的值,否則會引起錯誤;
  • #EXTINF —該標籤描述了媒體段的時長,在3.0版本後時長可以是浮點數,否則必須是整數。

2. 播放器本地代理

(1) 播放器直連Server

以企鵝輔導為例,播放器直連遠端Server的播放流程如下圖所示:

騰訊課堂點播上雲客戶端實踐總結 5

該流程存在一些缺點,比如:用戶播放視頻的時候可能等待的時間較長,造成流量的浪費,無法做緩存、預加載等優化策略等。

(2) 通過本地代理播放

基本流程如下圖所示:

騰訊課堂點播上雲客戶端實踐總結 6

企鵝輔導詳細流程如下圖所示:

騰訊課堂點播上雲客戶端實踐總結 7

具體流程可以概括為:

  • 啟動本地代理服務器(一期採用mongoose);
  • 視頻源地址傳給本地代理服務器;
  • 將視頻源地址轉換成本地代理服務器(127.0.0.1)的地址作為播放器的視頻源地址;
  • 播放器向本地代理服務器發送請求;
  • 本地代理服務器截取這個請求,再根據解析出來請求的信息向遠端服務器發起請求;
  • 本地代理服務器開始接受數據,寫入文件並將文件數據再返回到播放器;
  • 播放器接收到這些數據之後播放。

目前是使用mongoosehttps://github.com/cesanta/mongoose)來實現本地Http Server,在這裡簡單介紹一下mongoose。

mg_mgr:用於管理連接、事件等的 Manager ;mg_connection:單個連接,保存了連接信息。

主要用法步驟

  1. 調用mg_mgr_init進行初始化;
  2. 調用mg_bind,第2個參數為需要監聽的端口號,第3個參數為處理請求的handler;
  3. 調用mg_set_protocol_http_websocket將上一步返回的mg_connection與內建的http handler綁定。這樣我們的handler才能收到http事件;
  4. 通過一直調用mg_mgr_poll接收請求。

(3) Cache功能

使用本地代理一個重要作用就是Cache。

  1. 首先緩存m3u8文件內容;
  2. 當播放器請求第1個ts分片,異步請求下一個ts分片並緩存數據;
  3. 當播放器請求分片data時,內存有就內存返回,內存沒有就向遠端Server請求。

緩存淘汰

假定用戶經常看的視頻不能優先淘汰,那麼用 LFU 淘汰策略即可。每個緩存塊設置一個count,緩存命中一次就 count++,觸發淘汰的時候,把 count 最小的先淘汰。

流量控制

例如用戶只看了視頻前面一點,就暫停了,那麼後面的視頻不再下載等,具體細節後續文章將會詳細說明。

seek

播放視頻的時候,用戶會拖動進度條進行seek,與 mp4 文件不同,對於 hls 文件 ffplay 會根據 seek 的 position,向本地服務器請求 seek 的 position 所在的 ts 分片。

3. 騰訊課堂雲點播在線播放時序圖解析

騰訊課堂點播上雲客戶端實踐總結 5

如上圖所示:

  • 第一步通過業務 get_token 協議拿到防盜鏈需要的Key。這裡需要注意的是防盜鏈的Key順序一定要按照騰訊雲文檔中的順序,帶KEY防盜鏈的視頻播放地址的校驗工具;
  • 第二步通過騰訊雲 getplayinfo 協議拿到播放的鏈接,這裡的鏈接 master和 transcodelist 都會返回;
  • 第三步在請求的 URL 中拼接 voddrm.token 參數,用於鑑權;
  • 第四步將請求的 URL 透傳給教育自研的播放器 ARMPlayer,ARMPlayer會啟動本地代理,請求數據/解碼/渲染。課堂採用的是HLS加密 (1),所以播放的時候還需要通過DK(密鑰)進行TS解密。

4. 課堂騰訊雲點播本地播放時序圖解析

騰訊課堂點播上雲客戶端實踐總結 7

如上圖所示:

  • 第一步啟動本地代理,通過上層透傳的本地存儲的URL,讀取DB中的指定清晰度的 m3u8 鏈接和指定清晰度的 m3u8 的內容;
  • 第二步改寫 m3u8 鏈接和 DK/TS 的域名為:127.0.0.1;
  • 第三步請求本地 DK 和 TS 數據;
  • 第四步解密/解封裝/渲染。

二、課堂騰訊雲點播優化

1. 首幀優化

首幀的主要耗時點有:

  • master.m3u8 透傳給FFmpeg,FFmpeg 會串行拉取3個清晰度的m3u8及第1個TS分片;
  • DNS解析耗時高;
  • 每個清晰度.m3u8大小是400kb左右,拉取慢;
  • DK和TS每次都需要拉取。

騰訊課堂點播上雲客戶端實踐總結 10

點播首幀優化前請求流程

這裡面可能會涉及到一些問題,下面給出它們的解決方案。

問題1:master.m3u8透傳給FFmpeg,FFmpeg會串行拉取3個清晰度的m3u8及第1個TS分片。

騰訊課堂點播上雲客戶端實踐總結 11

指定清晰度.m3u8

解決方案:

  • getplayinfo協議直接獲取指定清晰度m3u8,減少master.m3u8 ->清晰度.m3u8的網絡請求;
  • 播放器從master.m3u8改為指定清晰度.m3u8透傳給FFmpeg,減少avformat_find_stream_info串行拉取3個清晰度和第1個TS分片的耗時。

問題2:DNS解析耗時高。

騰訊課堂點播上雲客戶端實踐總結 12

DNS緩存

解決方案

  • 增加DNS結果緩存模塊,緩存“{域名: IP}”;
  • 視頻播放時,直接查表,取出域名對應的IP地址。

問題3:每個清晰度.m3u8大小是400kb左右,拉取慢

解決方案

  • 預加載;

  • 預加載策略

    預加載學生報名直播課結束1週內的m3u8數據和指定位置的TS、DK。

問題4:DK和TS每次都需要拉取

騰訊課堂點播上雲客戶端實踐總結 13

本地代理緩存

解決方案

播放器設計了一個本地代理層,播放器不直連遠端server,而是通過本地代理層發出請求,通過本地代理層實現緩存和讀取本地資源進行播放。

2. 播放成功率優化

對於播放成功率,最主要是要完善監控系統以及對出現的問題各個擊破,目前遇到的主要問題和解決方式如下:

騰訊課堂點播上雲客戶端實踐總結 14

主要問題和解決方式1

騰訊課堂點播上雲客戶端實踐總結 15

主要問題和解決方式2

3. 播放體驗優化

  • ffplay音視頻同步;
  • 企鵝輔導錄播多路視頻流精確對齊。

騰訊課堂點播上雲客戶端實踐總結 16

精確Seek流程

4. 下載優化

  • 下載成功率

    因為教育自研的播放器下載和播放底層庫共用,所以除了播放出現的類似問題,下載方面我們還針對存儲、寫磁盤、安全性做了優化,已下載視頻採取DB分級映射緩存。

  • 下載速度

    因為HLS是由無數個TS和DK構成,如果是單線程下載,每次請求一個TS和DK地址都將重新建立連接,所以這裡我們採用的是多線程以及播放緩存復用邏輯。

5. 緩衝優化

這裡存在兩個問題,下面來做出解決方案。

問題1:舊播放器在讀數據 -> 解封裝 -> 解碼 -> 渲染鏈路上均出現過因為抖動而出現的緩衝。

騰訊課堂點播上雲客戶端實踐總結 17

緩衝區

解決方案

  • 幀緩衝區,抵抗網絡抖動和解碼抖動;
  • 顯示緩衝區,抵抗渲染抖動。

問題2:舊播放器是順序存儲同時沒有異步請求後面的TS分片和DK。

騰訊課堂點播上雲客戶端實踐總結 18

多線程和存儲

解決方案

  • 順序存儲和Seek之後的非順序存儲;
  • 多線程異步請求。

6. 安全性優化

  • 防盜鏈,騰訊雲防盜鍊主要有2種形式Referer防盜鍊和Key防盜鏈,目前課堂採用的是Key防盜鏈,騰訊雲防盜鏈(2);
  • HLS加密;
  • 水印。

三、課堂騰訊雲點播踩過的坑

因為騰訊課堂不僅是新生成或上傳的視頻要上雲,同時對於之前存量的幾百萬MP4視頻要重新轉碼上傳到雲上,這個過程中容易踩到不少坑。這裡提供一些常見的問題以及解決方案。

1. 轉碼出的視頻清晰度不全

這裡主要有2個原因:機構上傳的視頻清晰度較低,低轉高不一定能轉碼出來,其次1080p不一定能轉成功。

解決方案

  • 後台重新轉碼;
  • 客戶端健壯性,對於清晰度缺少的視頻播放和下載採用降級策略,降級到最近的清晰度最清晰的視頻。

2. 獲取騰訊雲播放鏈接是通過getplayinfo接口

回包中包括 master.m3u8 和 transcodelist 兩個信息,出現 master.m3u8 包含的清晰度個數和 transcodelist 清晰度個數不一致。

解決方案:後台重新轉碼。

3. 播放提前結束或seek不准確

HLS標準中的EXTINF 標誌的切片時間總和和TS分片實際的時間總和不一致,導致播放提前結束和Seek不准確。

解決方案:後台重新轉碼

4. 錄播視頻經過騰訊雲轉碼出現拉伸

機構上傳的原視頻不是標準的720,騰訊雲重新轉碼會出現拉伸。

解決方案:後台重新轉碼。

5. 播放一直加載中

因為存量視頻從原來的MP4視頻切到HLS,偶現從後台拉到的用戶上一次MP4播放進度同步到HLS,超過了HLS視頻總時長, 播放一直loading

解決方案:客戶端容錯, 超過視頻總時長將 Position 置為0。

除了上面視頻本身可能會出現的坑,還有客戶端灰度期間兼容兩種視頻源同時存在切換、Next學位和普通課程、回放分段視頻切換等也容易踩坑。目前課堂建立了完善的監控,第一時間發現解決問題。

從輔導到課堂,直播回放全量上雲,各項數據和用戶體驗都有了很大的提升,歡迎大家一起參與騰訊課堂點播上雲,一起為教育點播保駕護航!

參考資料

(1) HLS 加密:https://cloud.tencent.com/document/product/266/9638

(2) 騰訊雲防盜鏈:https://cloud.tencent.com/document/product/266/14047

本文轉載自公眾號雲加社區(ID:QcloudCommunity)。

原文鏈接

https://mp.weixin.qq.com/s/JdyL3VriaFegcoQcDj6KsQ