hls中的playlist(m3u8)

       最近忙着學習MSS(Microsoft smooth streaming),都忘了HLS的內容。最近遇到幾個bug都是hls seek有關,hls的精準seek問題,seek的最小單位是視頻分片(ts流),導致無法精準seek到關鍵幀。雖然說現在有的code不支持,就把這個bug推出去了。

      我在網上看到大量和我有類似的hls seek問題,我以爲是apple設計如此呢。(顯然不能甩鍋給apple)

今天經理告訴我一個方法就是可以通過seek到某一個視頻分片,下載後,到seek的時間點開始播放,這樣也可以做到精準seek。

     下面梳理一下hls的基礎知識:

playlist(m3u8)介紹

HLS中的playlist是一個UTF-8編碼的文本文件,其中包含了URL和描述性標籤。一個常規的playlist如下所示:

#EXT-X-VERSION:3
#EXTM3U
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:1
 
# Old-style integer duration; avoid for newer clients.
#EXTINF:10,
http://media.example.com/segment0.ts
 
# New-style floating-point duration; use for modern clients.
#EXTINF:10.0,
http://media.example.com/segment1.ts
#EXTINF:9.5,
http://media.example.com/segment2.ts
#EXT-X-ENDLIST

其中以'#'打頭的行都是標籤,HLS標準規定對於標準中未定義的標籤,可以直接忽略;也就是說'#'也可以作爲註釋行。這裏說明下上面M3U8文件的構成:

  • #EXT-X-VERSION:<n> 表示協議的版本號,而且每個M3U8中只能出現一次該標籤。對於具體版本號的定義,可以參考標準的第7節。
  • #EXTM3U作爲M3U文件的標識符,可以用於文件類型識別,這是必須的字段。
  • #EXT-X-TARGETDURATION:<s>表示最長分片的時長,這是必須的字段。
  • #EXT-X-MEDIA-SEQUENCE:<number>表示playlist文件中第一個分片的序列號(整數值)。如果M3U8文件中沒有該字段,則playlist中第一個分片的序列號必須是0。
  • #EXTINF:<duration>,[<title>]表示下一個分片的時長。對於每個分片,必須有該字段。 對於#EXT-X-VERSION小於3的情況下,duration必須是整數;其他情況下duration可以是浮點數和整數。title是一個可選字段,僅用於增強可讀性。
  • #EXT-X-ENDLIST 該字段表示分片結束,不會在playlist文件中添加新的分片。

上面介紹的是最常見的playlist,還有一種playlist,僅包含播放節目列表信息,在HLS中稱爲master playlist。其示例如下:

#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=1280000,AVERAGE-BANDWIDTH=1000000, RESOLUTION=720x480
http://example.com/low.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=2, BANDWIDTH=2560000,AVERAGE-BANDWIDTH=2000000, RESOLUTION=1080x720
http://example.com/mid.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=3, BANDWIDTH=7680000,AVERAGE-BANDWIDTH=6000000, RESOLUTION=1920x1080
http://example.com/high.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=4, BANDWIDTH=65000,CODECS="mp4a.40.5"
http://example.com/audio-only.m3u8

其中包含的標籤說明如下:
#EXT-X-STREAM-INF:<attribute-list>用於標識一個Variant Stream,這是由一系列的Redition組成的。該標籤的屬性列表中包含了Variant Stream的描述信息。例如:

  • BANDWIDTH表示Variant Stream中的峯值比特率,單位bits/s。
  • AVERAGE-BANDWIDTH表示Variant Stream中的平均比特率,單位bits/s。
  • CODECS包含Variant Stream中音視頻編碼格式相關的信息,比如上面的"mp4a.40.5"。
  • RESOLUTION包含Variant Stream中對應視頻流的分辨率。
  • FRAME-RATE表示Variant Stream中的視頻幀率。

M3U8中還有一個標籤需要關注下,EXT-X-PLAYLIST-TYPE。該標籤只有兩個值:EVENT、VOD。EVENT指的是分片工具只能在M3U8末尾添加新的分片的信息,但不能刪除老的分片,通常比較適用於直播+錄播的情況(既要提供給客戶端點播功能,也要對實時場景進行錄製,直播完成之後EVENT就自然退化爲VOD)。但是對於M3U8中存在#EXT-X-ENDLIST標籤時,可以忽略EXT-X-PLAYLIST-TYPE
還有一種情況,如果M3U8中不存在#EXT-X-ENDLIST以及EXT-X-PLAYLIST-TYPE標籤,則服務器端可以任意更新playlist內容。

3 服務器端和客戶端的主要實現邏輯

HLS之服務器端

在第一部分介紹過,HLS的服務器端包括三個部分:轉碼器、分片器、分發端。對於VOD而言,這三個部分是可以獨立工作的,並不需要太多的配合。但對於直播而言,三者需要密切配合,以保證直播的實時性和流暢度。典型的服務器端邏輯是這樣的:

  1. 將原始音視頻數據或者多媒體素材通過轉碼器編碼複用;
  2. 將複用後的文件切片,並生成對應的M3U8(注意切片應該符合HLS規範);
  3. 爲每個切片生成對應的URL,並更新M3U8文件;
  4. 直播需要實時更新Playlist對應的M3U8,點播生成完成之後服務器端不得修改Playlist

HLS之客戶端

從邏輯上來講,HLS客戶端更爲簡單。其典型處理邏輯如下:

  1. 通過給定URI獲取 Playlist。若是Master Playlist,客戶端需選擇一個Variant Stream來播放。
  2. 客戶端檢查#EXT-X-VERSION版本是否滿足。
  3. 客戶端應該忽略不可識別的 tags,忽略不可識別的屬性鍵值對。
  4. 加載Media Playlist file,並選擇一個segment開始播放;
  5. 播放完成一個segment之後,根據客戶端當前的具體情況選擇一個新的segment,並重復執行播放操作;
  6. 對於直播,需要定期刷新Media Playlist file,並選擇合適的segment播放。

4 碼率切換的基本邏輯

從HLS協議的定義來看,所有的碼率切換策略都是有客戶端定義的。服務器端僅僅提供幾種可供選擇的碼率。所以主要的碼率切換邏輯也是在客戶端完成。

客戶端判斷是否切換的主要因素如下:

  1. 設備實際下載速度
  2. 設備運行情況(CPU、內存、以及屏幕分辨率)

比較簡單的客戶端會直接根據實際下載速度和Variant Stream標稱的碼率做比較,如果滿足就上切,不滿足就下切。

當然在實際切換時還需要考慮播放器的用戶體驗,最好做到平滑切換,用戶沒有直接的可見的播放卡頓。

5 常見的開源HLS框架

到目前爲止,我所遇到的HLS播放框架主要有:ffmpeg中的HLS模塊、AOSP中的HLS模塊。當然在Mac或iOS中原生就支持HLS,不過沒有源碼。

參考自:https://www.cnblogs.com/tocy/p/stream-media-protocol-hls-overview-2.html

還有多種m3u8的格式:HLS playlist典型示例 

 

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