[时间:2018-03] [状态:Open]
[关键词:流媒体,stream,HLS]
本文是上一篇的后续部分,链接如下:HLS协议综述
2 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内容。
到此我们基本介绍了完了M3U8的格式。
3 服务器端和客户端的主要实现逻辑
HLS之服务器端
在第一部分介绍过,HLS的服务器端包括三个部分:转码器、分片器、分发端。对于VOD而言,这三个部分是可以独立工作的,并不需要太多的配合。但对于直播而言,三者需要密切配合,以保证直播的实时性和流畅度。典型的服务器端逻辑是这样的:
- 将原始音视频数据或者多媒体素材通过转码器编码复用;
- 将复用后的文件切片,并生成对应的M3U8(注意切片应该符合HLS规范);
- 为每个切片生成对应的URL,并更新M3U8文件;
- 直播需要实时更新Playlist对应的M3U8,点播生成完成之后服务器端不得修改Playlist
HLS之客户端
从逻辑上来讲,HLS客户端更为简单。其典型处理逻辑如下:
- 通过给定URI获取 Playlist。若是Master Playlist,客户端需选择一个Variant Stream来播放。
- 客户端检查#EXT-X-VERSION版本是否满足。
- 客户端应该忽略不可识别的 tags,忽略不可识别的属性键值对。
- 加载Media Playlist file,并选择一个segment开始播放;
- 播放完成一个segment之后,根据客户端当前的具体情况选择一个新的segment,并重复执行播放操作;
- 对于直播,需要定期刷新Media Playlist file,并选择合适的segment播放。
4 码率切换的基本逻辑
从HLS协议的定义来看,所有的码率切换策略都是有客户端定义的。服务器端仅仅提供几种可供选择的码率。所以主要的码率切换逻辑也是在客户端完成。
客户端判断是否切换的主要因素如下:
- 设备实际下载速度
- 设备运行情况(CPU、内存、以及屏幕分辨率)
比较简单的客户端会直接根据实际下载速度和Variant Stream标称的码率做比较,如果满足就上切,不满足就下切。
当然在实际切换时还需要考虑播放器的用户体验,最好做到平滑切换,用户没有直接的可见的播放卡顿。
5 常见的开源HLS框架
到目前为止,我所遇到的HLS播放框架主要有:ffmpeg中的HLS模块、AOSP中的HLS模块。当然在Mac或iOS中原生就支持HLS,不过没有源码。
6 总结
后面的文章将中主要关注ffmpeg和AOSP中的HLS相关的实现。同时会给出一个基于ffmpeg搭建的HLS直播系统(本地文件模拟的直播源)。
本文主要简单总结了HLS协议相关的基础知识,以及HLS服务器端和客户端的常规实现逻辑。仅供后续参考及查阅。