HLS全称为HTTP Live Streaming,其中m3u8作为描述协议,指向一系列切片文件。支持多码流与自适应码率,支持广告无缝播放,支持CMAF协议的低延时直播,也支持CDN动态选择。
我们先看下HLS整体架构,由三部分构成:服务端、CDN分发、客户端,切片文件可以是ts或者mp4。如下图所示:
一、自适应码率
服务端提供多个不同码率的码流,客户端根据估计的码率来选择最合适的码流,实现自适应码率的流畅播放。码流描述使用EXT-X-STREAM-INF表示,BANDWIDTH表示带宽,RESOLUTION表示分辨率,如下所示:
#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=150000,RESOLUTION=416x234,CODECS="avc1.42e00a,mp4a.40.2"
http://example.com/low/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=240000,RESOLUTION=416x234,CODECS="avc1.42e00a,mp4a.40.2"
http://example.com/lo_mid/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=440000,RESOLUTION=416x234,CODECS="avc1.42e00a,mp4a.40.2"
http://example.com/hi_mid/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=640000,RESOLUTION=640x360,CODECS="avc1.42e00a,mp4a.40.2"
http://example.com/high/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=64000,CODECS="mp4a.40.5"
http://example.com/audio/index.m3u8
二、广告无缝播放
视频和广告的编码器参数往往不同,所以在插播广告时,需要重新创建解码器,有一定耗时。m3u8为了解决这个问题,引入EXT-X-DISCONTINUITY来标识前后切片参数不同,让客户端可以提前初始化解码器。m3u8描述如下:
#EXTM3U
#EXT-X-TARGETDURATION:10
#EXT-X-VERSION:4
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.0,
ad0.ts
#EXTINF:8.0,
ad1.ts
#EXT-X-DISCONTINUITY
#EXTINF:10.0,
movieA.ts
#EXTINF:10.0,
movieB.ts
使用AVQueuePlayer进行无缝播放,示例代码如下:
let player = AVQueuePlayer()
let item1 = AVPlayerItem(url: url1)
let item2 = AVPlayerItem(url: url2)
player.insert(item1, after: nil)
player.insert(item2, after: item1)
player.play()
三、低延迟直播
HLS的低延迟直播基于CMAF协议(Common Media Application Format)。CMAF由四部分组成:
- CMAF Track:包含video、audio、subtitle轨道;
- CMAF Header:轨道头部信息,比如视频的宽高、分辨率,音频采样率、声道数;
- CMAF Segment:轨道的一系列片段;
- CMAF Chunk:Segment的分片,若干个Chunk组成一个Segment;
关于CMAF的结构示意图如下:
在认识CMAF协议后,我们看下Low-Latency HLS的关键点:生成segment分片(chunk)、Playlist增量更新、使用预加载提示、切换码率过渡上报。
1、生成segment分片
在CMAF协议中,segment还可以划分更小单元——chunk。每个chunk块有更短的时长,易于打包、发布、传输。例如,一个时长为6s的segment划分30个chunk,那么每个chunk时长仅有200ms。使用EXT-X-PART标签来表示chunk分块。
2、Playlist增量更新
使用EXT-X-SKIP标签实现增量更新,降低传输成本。
3、阻止列表重新加载
低延迟协议支持阻止播放列表重新加载,避免浪费带宽。当客户端发起HTTP请求更新列表时,指定需要更新的segment。服务端收到请求后,先保持住请求,等待segment准备就绪,然后push推送给客户端。
4、预加载提示
为了消除不必要的RTT等待,服务端使用EXT-X-PRELOAD-HINT标签,来通知客户端预加载下一个segment。
5、切换码率过渡上报
低延迟播放,客户端支持以最少的RTT数来切换码率,实现码率自适应。使用EXT-X-RENDITION-REPORT标签来携带媒体序列号、分块等信息。
四、CDN动态选择
CDN架构包括:origin源站和edge边缘节点。客户端会就近访问边缘节点,如果命中缓存,那么直接使用缓存;如果不命中缓存,回溯到源站去请求,简称为回源。架构如下图所示:
提供PATHWAY-ID来选择CDN,使用EXT-X-CONTENT-STEERING来指定选中的CDN,描述如下:
#EXTM3U
#EXT-X-CONTENT-STEERING:SERVER-URI="/steering?video=00012",PATHWAY-ID="CDN-A"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=“A”,NAME="English",DEFAULT=YES,
LANGUAGE="en",URI="audio.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=“B”,NAME=“ENGLISH”,DEFAULT=YES,
LANGUAGE="en",URI="https://backup.example.com/content/videos/video12/
audio.m3u8" #EXT-X-STREAM-INF:BANDWIDTH=1280000,AUDIO="A",PATHWAY-ID="CDN-A"
low/video.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=7680000,AUDIO="A",PATHWAY-ID="CDN-A"
hi/video.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1280000,AUDIO="B",PATHWAY-ID="CDN-B"
https://backup.example.com/content/videos/video12/low/video.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=7680000,AUDIO="B",PATHWAY-ID="CDN-B"
https://backup.example.com/content/videos/video12/hi/video.m3u8
提供PATHWAY-PRIORITY来表示各个CDN路径的优先级,排在前面的优先级最高。另外用TTL标识客户端等待时间,默认为300s。使用json格式描述,如下所示:
{
"VERSION": 1,
"TTL": 300,
"RELOAD-URI": "https://example.com/steering?video=00012&session=123",
"PATHWAY-PRIORITY": [
"CDN-A",
"CDN-B"
]
}