HTTP Live Streaming(HLS)是蘋果公司提出來的流媒體傳輸協議。與RTP協議不同的是,HLS可以穿透某些允許HTTP協議通過的防火牆。
一、HLS播放模式
(1) 點播模式(Video on demand, VOD)
點播模式是指當前時間點可以獲取到所有index文件和ts文件,二級index文件中記錄了所有ts文件的地址。這種模式允許客戶端訪問全部內容。上面的例子中就是一個點播模式下的m3u8的結構。
(2) 直播模式(Live)
直播模式是指實時生成M3u8和ts文件。它的索引文件一直處於動態變化的,播放的時候需要不斷下載二級index文件,以獲得最新生成的ts文件播放視頻。如果一個二級index文件的末尾沒有#EXT-X-ENDLIST標志,說明它是一個Live視頻流。
客戶端在播放VOD模式的視頻時其實只需要下載一次一級index文件和二級index文件就可以得到所有ts文件的下載地址,除非客戶端進行比特率切換,否則無需再下載任何index文件,只需順序下載ts文件並播放就可以了。但是Live模式下略有不同,因為播放的同時,新ts文件也在被生成中,所以客戶端實際上是下載一次二級index文件,然后下載ts文件,再下載二級index文件(這個時候這個二級index文件已經被重寫,記錄了新生成的ts文件的下載地址),再下載新ts文件,如此反復進行播放。
如果HLS的索引文件分為2級,那么第一級的index文件稱為Master PlayList,可能包含着各種分辨率的index地址,選定某一個地址后,獲取的index文件是第二級,Media PlayList。 保留着每一個#EXT-X-STREAM-INF的下一行是二級index文件的路徑,可以用相對路徑也可以用絕對路徑。這個文件中記錄了不同比特率視頻流的二級index文件路徑,客戶端可以自己判斷自己的現行網絡帶寬,來決定播放哪一個視頻流。
測試的HLS地址:http://live.hkstv.hk.lxdns.com/live/hks/playlist.m3u8(Live)
http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8(VOD)
二、m3u8文件的格式
在開始流媒體會話時,客戶端首先會獲取一個m3u8文件,用於獲取可以播放的媒體列表。 首先了解m3u8文件中幾個標簽的含義:
#EXTM3U // m3u文件頭,必須放在第一行 #EXTINF // extra info,分片TS的信息,如時長,帶寬等 #EXT-X-TARGETDURATION// 指定當前視頻流中的切片文件的最大時長 #EXT-X-PLAYLIST-TYPE:VOD // 表示這是一個VOD文件 #EXT-X-ALLOW-CACHE // 是否允許cache #EXT-X-ENDLIST // m3u8文件結束符
在VLC輸入上邊VOD測試地址,點擊播放后,就會向特定的服務器獲取m3u8文件,一個普通的m3u8文件格式如下:
#EXTM3U #EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=200000 gear1/prog_index.m3u8 #EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=311111 gear2/prog_index.m3u8 #EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=484444 gear3/prog_index.m3u8 #EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=737777 gear4/prog_index.m3u8
上述文件表示不同分辨率的m3u8文件地址,獲得該文件后,VLC會根據本地帶寬選定使用的m3u8文件,然后打印如下日志:
httplive stream debug: bandwidth adaptation detected (program-id=1, bandwidth=200000).
access_http access debug: http: server='devimages.apple.com' port=80 file='/iphone/samples/bipbop/gear1/prog_index.m3u8'
可見,此時VLC選定了bandwidth=200000的選項,然后VLC就會下載該選項對應的m3u8文件,該m3u8文件指定了要下載的ts文件的列表及地址。由於是VOD模式,m3u8文件是全的,最后也有“#EXT-X-ENDLIST”標識。
#EXTM3U #EXT-X-TARGETDURATION:10 #EXT-X-MEDIA-SEQUENCE:0 #EXTINF:10, no desc fileSequence0.ts #EXTINF:10, no desc fileSequence1.ts #EXTINF:10, no desc fileSequence2.ts #EXTINF:10, no desc fileSequence3.ts ...... #EXTINF:10, no desc fileSequence178.ts #EXTINF:10, no desc fileSequence179.ts #EXTINF:1, no desc fileSequence180.ts #EXT-X-ENDLIST
三、使用VLC調試HLS協議
在之前的分析中介紹過,播放一個視頻通常是access->demux->decoder->render的流水線過程,有時access和demux的過程會合在一起,比如播放RTSP攝像頭時,access和demux都在Live555模塊內進行。在讀取HLS視頻流時,access使用的是http+httplive模塊,demux模塊使用的是libts(之前的分析中有介紹),decoder一般是FFmpeg,render在不同的平台上會使用不同的模塊(Windows一般是DShow,Android一般是OpenGL)。了解了播放HLS視頻源所使用的模塊,可以在對應模塊的Open函數中設置斷點,調試其模塊打開過程,以學習HLS。在modules\access\http.c文件中打印了如下信息:
access_http access debug: http: server='live.hkstv.hk.lxdns.com' port=80 file='/live/hks/playlist.m3u8'
當點擊播放測試的HLS地址后,VLC首先創建了一個access模塊(http),http模塊主要的工作就是進行http通信,由於通信過程中下載的文件格式是m3u8,因此還需要一個stream filter模塊(httplive),也就是說解析m3u8格式是在httplive模塊進行的。httplive模塊在開啟時,會創建hls_Thread線程不斷的去下載ts文件,而且如果是實時播放模式的話,還會創建hls_Reload線程去更新ts文件列表。httplive會不斷調用http去下載最新的ts文件,下載的ts數據文件中的數據(有視頻有音頻)保存在httplive模塊。在得到了視頻音頻數據后,接下來要做的就是demux。libts在調用Demux函數在分離時,會調用ReadTSPacket函數,該函數會讀取httplive模塊下載好的ts數據,將這些ts數據分離至視頻和音頻FIFO,之后就是視頻和音頻decoder的事情了,不再贅述。
注意在實時播放模式下,播放HKS實時視頻時,獲得的ts流地址采用類似滑動窗口的形式,比如,第一次hls_ReloadPlaylist獲得的m3u8文件中ts的數字是373363.ts、373364.ts和373365.ts,那么第二次hls_ReloadPlaylist時,獲得的m3u8文件中ts的數字就是373364.ts、373365.ts和373366.ts,每次向后加1.
參考資料:
(1) 官方文檔:https://github.com/jiayayao/DataSheet/tree/master/stream%20protocol/hls
(2) http://www.jianshu.com/p/426425cad08a
附:
配置好的Windows版vlc工程下載:https://github.com/jiayayao/vlc_2.1.0-vs_2010,下載后使用vs2010可以直接編譯運行,調試學習非常方便。