天天看點

HLS協定

HTTP Live Streaming(HLS實時流)大白話了解:其實就是規定一種封裝和傳輸方式。以我的了解來說,首先原始資料經過音頻/視訊編碼後,變成編碼完的裸資料,再按照一定的标準進行封裝(比如hls中規定了索引檔案m3u和切片ts的不同封裝标準),然後基于HTTP協定進行傳輸(傳輸過程中,主要對服務端和用戶端進行了一些規定,要求按照标準來生成hls和應用hls)。

先來看一個别人寫的文檔——(Apple官網的文檔那也是相當古老的)

1.這個裡面講了一些基本點,比較古老 HTTP Live Streaming (HLS) - 概念

2.這個裡面更多提到了HLS包含的分片,支援的格式,以及對索引檔案的每個标簽做了詳細解釋。 HLS協定概述

一、基本介紹

一些知識點:

  • 由Apple提出和開發,但并不是僅僅使用在ios系統上,目前在各種終端均得到了支援。
  • 雖然是實時流,但可以用于直播(live)和點播(vod)場景,點播就是在索引檔案結束處有一個#EXT-X-ENDLIST标志。
  • 點播隻需要請求一次索引檔案(包含切片名稱的那個索引檔案),而直播場景下,伺服器會不斷産生新的切片,是以播放端也要間隙性地重新整理索引檔案。播放器一般是根據EXT-X-MEDIA-SEQUENCE,可能還會結合清單中ts片的數目,判斷m3u8是否更新,然後決定是否需要請求新的m3u8。
  • 播放器拿到索引清單後,一般是根據m3u8中的#EXT-X-TARGETDURATION, 比如間隔1/2(或1/3)的EXT-X-TARGETDURATION請求下一片ts。播放器不同,政策也不同,這個是工業場景比較重要的播放優化點。
  • 服務端可以采用軟編或硬編來生成hls。目前Apple官方文檔提到,他們預設的Server端編碼方式是HEVC(H.265),貌似在哪兒看到寫死會使用H.265,軟編碼更多人使用H.264。反正國内很多網際網路公司生成hls流時會更多使用H.264。(更奇怪的是,在Apple官網的問答子產品,他們卻隻字未提H.265)
  • 至于生成的hls流中,使用的視訊壓縮标準可以是H.265或者H.264,音頻壓縮标準可以是AAC或者AC-3。
  • HLS是支援動态碼率(即碼率自适應)的,但這個動态碼率僅限于不同的ts分片之間。(在編碼中途,不要修改視訊編碼器的設定,比如視訊大小或者編碼解碼器類型。如果避免不了,那修改動作必須發生在一個片段邊界。并且需要在之後相連的片段上用 EXT-X-DISCONTINUITY進行标記。)(用戶端和分發的服務端能根據網絡環境自适應地請求和發送不同碼率的分片。比如服務端對同一音視訊内容緩存了多個不同碼率的分片,用戶端接收速度較慢,則發送碼率較低的分片;反之則發送碼率較高的分片但這依賴服務端生成"主-從"形式的動态索引結構。具體見前面引用的第1篇文章。)
  • 索引檔案可能以.m3u8/.m3u為标記結束,其中.m3u一般用于mp3音頻流的索引。索引檔案的格式參考前面引用的文章或Apple官網。用于動态切換碼率的主-從形式的動态索引結構,可以使用Apple官網提供的variantplaylistcreator生成。無論是點播還是直播場景,都可以使用動态索引結構。(值得注意的是,在國内網際網路公司使用hls的場景中,為了降低服務端生成/存儲/分發流的負載,或者由于用戶端對動态切換碼率适配不夠,通常并沒有使用這個功能。)
  • 雖然我們常見的hls流中,包含音視訊媒體資料的切片都是ts檔案(MPEG-2 Transport Streams),但實際上hls流中還可以支援fMP4檔案和純音頻檔案(Packed Audio),WebVTT,具體見前面引用的第2篇文章。

二、某些知識點重點介紹

動态切換碼率(碼率自适應)

背景:Apple官方的裝置都是支援動态切換碼率的,這除了對切片器有要求外,更多的是對播放終端的适配性要求。但國内使用hls流播放的場景,通常并不是這樣,因為我們同樣的流,可能在PC端,web端,Android端和ios端都要播放,播放器可能使用的是自己開發的或第三方SDK,不能很好地适配碼率切換這個功能。

這方面的文章不算特别多,這裡簡單寫下我的了解。

由于沒有找到比較官方的翻譯,這裡我們暫時定義結構圖中的Index file為主索引檔案,Alternate index file為動态索引檔案。

  • 1)這兩者都是.m3u8格式;
  • 2)主索引檔案隻需下載下傳一次,但直播場景下動态索引檔案需要下載下傳多次,主索引檔案負責給出各個動态索引檔案的參數和位址,動态索引檔案負責給出具體的ts分片資訊;
  • 3)位于索引結構中(主索引檔案清單中有順序的)的第一個索引關聯着用戶端預設使用的流,但用戶端可以根據網絡環境随時動态切換到其他流;
  • 4)不同流應使用同樣的音頻檔案;
  • 5)通常而言,如果條件允許,應盡可能編碼足夠多的不同碼率的流來适應不同網絡環境(以保證流暢播放);
  • 6)建議在動态索引檔案命名時加上路徑/碼率等一些有差別性的字段;
  • 7)同一視訊内容的不同碼率流,雖然分辨率不同,但應保持寬高比一緻;
  • 8)動态索引檔案中EXT-X-STREAM-INF内的RESOLUTION字段應盡可能标出,以協助用戶端根據需要切換合适的流;
  • 9)如果将同一視訊内容的不同碼率流存儲在不同伺服器上,那麼這些流除了可供動态切換碼率以外,還能作為某一路流請求失敗的備份流。比如見示例,ALPHA和BETA伺服器上的流其實内容和碼率都一緻,僅為備份使用。
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=200000, RESOLUTION=720x480
http://ALPHA.mycompany.com/lo/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=200000, RESOLUTION=720x480
http://BETA.mycompany.com/lo/prog_index.m3u8
 
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=500000, RESOLUTION=1920x1080
http://ALPHA.mycompany.com/md/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=500000, RESOLUTION=1920x1080
http://BETA.mycompany.com/md/prog_index.m3u8
複制代碼
           
  • 10)動态索引檔案中可以指定編碼方式,如下面示例中的CODECS屬性,但是要記得用雙引号。
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=500000, RESOLUTION=720x480
mid_video_index.M3U8
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=800000, RESOLUTION=1280x720
wifi_video_index.M3U8
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=3000000, CODECS="avc1.4d001e,mp4a.40.5", RESOLUTION=1920x1080
h264main_heaac_index.M3U8
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=64000, CODECS="mp4a.40.5"
aacaudio_index.M3U8
複制代碼
           
  • 11)如果在多個動态索引檔案中,包含了一個音頻流,那麼可以在主索引檔案中指定,如下所示:
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=500000, RESOLUTION=1920x1080
mid_video_index.M3U8
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=150000, RESOLUTION=720x480
3g_video_index.M3U8
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=64000, CODECS="mp4a.40.5"
aacaudio_index.M3U8
複制代碼
           
  • 12)主索引檔案中列出來的動态索引檔案路徑,可以是絕對路徑,也可以是相對路徑。以上第一個示例為絕對路徑,第二、三個示例為相對路徑。

音頻流或靜态圖流

  • 1)建立音頻流,在切片時加入-audio-only的指令即可
  • 2)建立靜态圖流,如以下示例,-meta-file為指定的靜态圖檔,-meta-type=picture為固定的指令。
mediafilesegmenter -f /Dir/outputFile -a --meta-file=poster.jpg --meta-type=picture track01.mp3
複制代碼
           

三、改進HLS技術

相較于其他媒體傳輸協定,hls雖然有一些自己的優勢,但也有很顯而易見的劣勢。(具體見不同音視訊傳輸協定的對比)那商業場景中使用hls作為傳輸協定時,如果盡可能去避免它的劣勢呢?

  • 1).改進hls中http請求無狀态的特性,用以有效區分不同的播放端,保證及時定位排查問題——可以通過在ts分片的URL中添加sessionId或者uuid之類的東東,來區分不同的連接配接。
  • 2).改進hls中延時較高的問題——HLS在直播場景中,相對于其他流媒體協定而言,延時一般在10s~35s左右,非常高。

    HLS 理論上延時=1個切片的時長+ 0-1個td(td是EXT-X-TARGETDURATION,可簡單了解為播放器取片的間隔時間) + 0-n個啟動切片(蘋果官方建議是請求到3個片之後才開始播放) + 播放器最開始請求的片的網絡延時(網絡連接配接耗時)。

    改進hls直播延時需要從延時構成上逐一突破:1.服務端編碼和切片子產品生成切片檔案的耗時(這個可以從提高服務端性能,縮短切片檔案時長和大小來做);2.播放器取片間隔時長(仍舊是切片檔案大小);3.用戶端啟動切片個數(這個可以在用戶端做優化,盡可能啟動播放前下載下傳較少的切片,同時保證音視訊的同步);4.用戶端下載下傳和解碼耗時(這部分主要是網絡連接配接的優化以及用戶端解碼器的優化)

  • 3).P2P傳輸——這是比較進階的技術支援,在用戶端的各個節點間完成。要保證切片檔案比較小(由于P2P傳輸是不可靠的,太大的切片檔案會導緻大量傳輸失敗和重傳,造成整個P2P網絡嚴重的資源浪費)。此外仍舊不太适用于實時性要求很高的無延時P2P,如上文3.2中所述,hls協定中的延時來自于各個環節,如果單個切片檔案時長要求控制在幾十毫秒,實作難度極其高。