HLS目前被浏览器支持的比较好,safri、chrome、Edge都支持使用video标签直接播放HLS的视频。但其实时性相对较差,一般延时要在5秒+。
播放端通过两个业务交互来达成视频的播放,一是获取视频清单,在HLS中,一个完整的视频会被分割成多个TS视频,播放端无缝有序播放这些TS视频,最终达成视频的完整播放。二是获取视频清单中指定的TS视频文件。
首先来介绍下HLS中的视频清单,也就是m3u8,它其实就是一个playlist,它家的主要成员如下:
#EXTM3U 文件的魔术字
#EXT-X-VERSION:3 文件的版本信息
#EXT-X-TARGETDURATION:10 目标的视频时长
#EXT-X-ALLOW-CACHE:YES 是否允许信息缓存
#EXT-X-MEDIA-SEQUENCE:10 下面显示的媒体文件第一个的序号
#EXTINF:3.0,
https://www.ts.com/10.ts TS文件时长以及下载路径,可以是绝对或相对路径
#EXTINF:3.0,
https://www.ts.com/11.ts
#EXT-X-ENDLIST 代表已经获取了所有的媒体文件,无需再次向服务器刷新媒体清单。
下面是两个清单样本:
Full PlayList
#EXTM3U
#EXT-X-TARGETDURATION:10
#EXT-X-VERSION:3
#EXTINF:9.009,
http://media.example.com/first.ts
#EXTINF:9.009,
http://media.example.com/second.ts
#EXTINF:3.003,
http://media.example.com/third.ts
#EXT-X-ENDLIST
Live PlayList
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:8
#EXT-X-MEDIA-SEQUENCE:2680
#EXTINF:7.975,
https://priv.example.com/fileSequence2680.ts
#EXTINF:7.941,
https://priv.example.com/fileSequence2681.ts
#EXTINF:7.975,
https://priv.example.com/fileSequence2682.ts
拥有#EXT-X-ENDLIST代表告知浏览器所有的媒体清单都已获取,无需再刷新m3u8文件了。而不拥有这个标识的,意味着后续还会有新的媒体文件出现,需要等下再次刷新,这个适合直播的场景。
此处备注:清单不需要包含历史出现的所有媒体文件,但尽量能够做到前一个和后一个有交叉,没交叉也没问题,主要提供给人为识别,前端通过#EXT-X-MEDIA-SEQUENCE,得到清单中每个文件的SEQUENCE,然后按照从小到大的顺序进行无缝播放。
对于点播,使用m3u8的方式,能够更方便用户的快速播放位置跳转,而使用mp4方式,则可能需要等待下载完成,才能有效跳转。
下面重点描述的是通过m3u8的方式,实现直播的效果。
服务端收到视频数据,按照时间段进行数据分段存放,一般3秒到5秒的TS数据,并且每个TS数据都给予一个流水号,持续增加,不减小。
当m3u8请求到来时,把最近的2个TS文件信息组装到playlist中,并返回给请求方,请求方后续会调用palylist中的ts数据地址,来获取TS数据进行播放。
当请求方再次来请求时,获得之前已发送到的序号,从已发送的序号开始,把后续所有已生成的TS片段都打进playlist中进行返回,求方后续会调用palylist中的ts数据地址,来获取TS数据进行播放。
如此循环,直到请求方关闭播放或者服务器返回携带#EXT-X-ENDLIST的Playlist,此时结束m3u8的循环查询,后续可能还会下载下最后一个playlist中尚未下载的TS数据。
备注1:服务端要按时间段组装TS数据包,并且在数据包被消费、超时或者超容量的情况下,应该被清理。Playlist永远是上次已返回的最后一个序号开始,到当下所有有效的TS数据包,如果是首次,那么取得当前时间往前推1到2个TS数据包,取决于你想让用户的延迟度有多大。
备注2: 上面是直播的情况,数据是先到服务端的,还有一种的是m3u8请求到达时,才去设备端进行视频数据获取的,那么此时可以在服务端阻塞下m3u8请求一定的时长,等到数据设备视频数据返回并至少生成一个TS数据包时,才返回首个playlist,避免返回空的playlist,导致不正常的播放行为。
备注3: 通常在进行m3u8请求时,会携带需要观看的视频信息以及访问端唯一性标识信息,用于服务端请求和匹配视频信息,同时访问端唯一性标识信息,也能让服务器对周期性的m3u8请求能够进行唯一性的关联识别。