什么是 HLS?
HLS(HTTP Live Streaming)1 是苹果公司开发的基于 HTTP 协议的流媒体网络传输协议。HLS 可以将流媒体文件切分成一个个小文件,然后通过 HTTP 协议传输。也因为被切分成一个个小的文件,当播放视频的时候,客户端可以同时加载后续的分段,当某个分段下载失败的时候可以单独进行重新下载。
HLS 协议的优势在于能够提供动态的、自适应的流媒体传输,当网络状况较差或者变好的时候,可以实时调整视频质量以适应不同网络环境和设备的能力。
HLS 支持的编码格式包括 AVC(H.264)、HEVC(H.265)、AAC(Advanced Audio Coding) 等,可以适应各种不同类型的音频和视频内容。此外,HLS 还支持多种传输协议,包括 UDP、RTP、RTSP、RTMP 等,以满足不同应用场景的需求。
下面是来自苹果官网的 编码和传送流媒体示意图:
- 硬件编码器接收到音视频输入,将其编码为 HEVC 视频和 AC-3 音频;
- 服务端输出分段的 MPEG-4 文件或者 MPEG-2 传输流;
- 服务端的分段器(Stream Segmenter)同时会将流分割成一系列的短媒体文件,并将它放置在 Web 服务器上;
- 服务端的分段器还会创建和维护一个包含媒体文件列表的索引文件,索引文件的 URL 会被发布到 Web 服务器上;
- 客户端会按照顺序请求所有的媒体文件,并在各个端上都能不间断进行播放展示;
时序图大致如下:
sequenceDiagram
participant A as Audio/Video Input
participant E as Media Encoder
participant S as Stream Segmenter
participant O as Origin Server
participant I as Index File
participant C as Client
A->>E: 1. Encode A/V into MPEG-4/MPEG-2 TS
E->>S: 2. Segment MPEG-4/MPEG-2 TS
S->>O: 3. Push segments to server
O->>I: 4. Create index file
O->>C: 5. HTTP delivery
I->>C: 6. Provide stream info
C->>C: 7. Play stream
HLS 作为一个整体的流媒体解决方案,会将音视频内容分割成一个个小文件,一般是 10 秒长度的 .ts
文件(Transport Stream),通过 HTTP 协议进行网络传输。
设想一下一个完整的 MP4 被切割成几百份、几千份 .ts
文件,如果没有个目录之类的东西,都不知道从哪里开始寻址或者应该上哪去找下一个片段的资源,因此 M3U/M3U8
文件正是起到了一个索引文件(index)的作用,列出所有流媒体碎片的位置,告知播放器怎么按照顺序进行下载播放的。
M3u & M3U8
MPEG
在提到 M3u/M3u8 之前,不得不提及 MPEG(Moving Picture Experts Group,动态图像专家组)2,它是一个国际标准化组织,专门负责为媒体编码制定标准,包括数字音频、视频、图形和基因组数据的压缩编码,以及各种应用的传输和文件格式。就像 JPEG(Joint Photographic Experts Group,联合图像专家组)3 制定一系列数字图像标准(JPEG、JPEG 2000、JPEG XR、JPEG XT、JPEG XS、JPEG XL…)一样,属于行业标准。
MPEG 专家组制定的一些比较出名的标准包括:
- MPEG-1: 设计初衷是为了在数字存储媒介(像 CD-ROM)上实现高效压缩音频和视频,以满足 VHS(Video Home System,家用录像系统)质量的视频,MPEG-1 Layer 3(也就是 MP3 格式)就是这个标准制定的,用于音频压缩。
- MPEG-2: 主要用在数字电视和 DVD 视频的编码。
- MPEG-3: 一开始是为了处理 1080P 的 HDTV(High-Definition Television) 信号,而 MPEG-2 同期的工作也在进行中,并且发现在高数据速率下也可以容纳 HDTV,所以 MPEG3 就被合并在了 MPEG-2 下。
- MPEG-4: 主要用于互联网视频、CD 分发的音视频数据压缩、语音(电话、视频电话)和广播电视等一些场景,MPEG-4 支持更高效的视频压缩,同时也支持多媒体功能,包含 3D 渲染、文件存储、支持同外部如 DRM(Digital Rights Management,数字版权管理)4 等类型进行交互。
- H.264/MPEG-4 AVC(Advaned Video Coding): 一种高效视频压缩标准,在网络流媒体到蓝光光盘等各种场景被广泛应用。它是一种基于块导向(block-oritended)、运动补偿编码(motion-compensated coding)的视频压缩技术,截止目前是最常用(90%+)的视频内容录制、压缩和分发格式,最高支持 8K UHD 分辨率。
- H.265/HEVC(High Efficiency Video Coding): 可以理解为 H.264 Plus,更高效、也为更高分辨率(4K、8K UHD)的视频提供压缩。同比 H.264 在相同视频质量的情况下,增加了 25-50% 的数据压缩(而在相同比特率下能够显著提高视频质量)。感兴趣可以看下雷神写的一篇对比文章5。
M3U
M3U(Moving Picture Experts Group Audio Layer 3 Uniform Resource Locator)5,简称 MP3 URL,用于多媒体播放列表的编排,也就是索引文件(index)。M3U 前面一大串就是上面提及的 MPEG。
M3U 在最开始是为了 Winamp6 播放器设计的,随着时间的推移,也得到了广泛的支持和应用,变成了一种通用的音/视频播放软件常用的播放列表格式。
M3U 是一种纯文本文件,它的结构也很简单:
- 文件头(
#EXTM3U
):用来标识当前文件是一个 M3U 格式,必须在文件的第一行。 - 跟踪信息(
#EXTINF
):也叫扩展信息,用来标识下方资源的播放时长(单位秒)和艺术家、显示标题。 - 媒体文件条目(
URL
):指向一个媒体文件,每个条目可以是本地文件(本地路径),或者是网上的流媒体地址(URL)。
一个 M3U 播放列表的示例:
M3U8
M3U 使用 Latin-1 字符集编码,而 M3U8 使用的是 UTF-8,所以它最后面的 8
是这么个意思。
因此如果文本使用本地系统的默认非 Unicode 编码(例如 Windows 代码页)进行编码,则该文件保存为 .m3u
文件扩展名;如果文本使用 UTF-8 编码,则保存为 .m3u8
扩展名。M3U 和 M3U8 都是苹果公司在 HLS 协议格式使用的基础。
下面我们通过一个小 demo 来实践了解下真实的 M3U8 长什么样子:
- 访问 30 Second Videos 下载一个 MP4 视频,假设你保存的文件叫
input.mp4
; - 通过
ffmpeg
将.mp4
转成.m3u8
文件(如果你未安装 ffmpeg 参考这里进行下载7,MAC 用户可以直接通过brew install ffmpeg
进行安装);
这段含义解释如下:
-i input.mp4
: 输入指定的文件,即上面假设的input.mp4
;-codec: copy
: 复制使用原始编解码器,避免进行转码(如果想要转码的话,可以指定具体的编解码器如-codec: libx264
);-start_number 0
: 设置生成的.ts
分段文件的起始编号;-hls_time 10
: 设置每个分段文件.ts
的长度,单位是秒;-hls_list_size 0
: 设置生成出来的 M3U8 播放列表中可包含的最大.ts
分段文件数量,0 表示不进行限制;-f hls
: 指定输出格式为HLS
- 查看当前目录,会发现多了几个文件,
.m3u8
和.ts
;
- 查看
.m3u8
文件内容;
- 尝试播放
.m3u8
文件,看看效果;
苹果公司将 M3U 格式作为 HLS 协议的基础,并且增加了一些标签或者说是扩展指令(Directives),都是以 #EXT-X-
开头。上面示例的 .m3u8
文件涉及到了其中一部分指令,让我们展开来看下都是什么含义:
Directive(指令) | 示例 | 描述 |
---|---|---|
#EXT-X-START | #EXT-X-START: TIME-OFFSET=0 | 指定播放列表的起始位置;TIME-OFFSET 表示距离第一个索引点的偏移时间 |
#EXT-X-VERSION | #EXT-X-VERSION: 4 | 指定播放列表版本 |
#EXT-X-TARGETDURATION | #EXT-X-TRAGETDURATION: 10 | 所有 .ts 文件片段的最大持续时间 |
#EXT-X-MEDIA-SEQUENCE | #EXT-X-MEDIA-SEQUENCE: 123456 | 所有 .ts 文件中第一个 .ts 文件片段的序号 |
#EXT-X-DISCONTINUITY | #EXT-X-DISCONTINUITY | 指明接下来的 TS 片段与前一个 TS 片段不是连续的;在插入广告的场景很有用 |
#EXT-X-PLAYLIST-TYPE | #EXT-X-PLAYLIST-tyPE: VOD | 指明播放类别类型,是 VOD(点播)还是 EVENT(直播) |
#EXT-X-KEY | #EXT-X-KEY : METHOD=AES-128,URI="key.key" | 指明解密 TS 片段所需要的密钥和方法 |
#EXT-X-ALLOW-CACHE | #EXT-X-ALLOW-CACHE: YES | 指定播放器是否可以缓存媒体数据 |
#EXT-X-ENDLIST | #EXT-X-ENDLIST | 播放列表结束标志,表示没有更多的 TS 片段了;如果是 EVENT 直播流,结尾就不存在这个标志 |
#EXT-X-STREAM-INF | #EXT-X-STREAM-INF: BANDWIDTH=640000,RESOLUTION=640x360,CODECS="avc1.42e00a,mp4a.40.2" | 指定下一个 URL 的属性,如 BANDWIDTH(指定码率)、RESOLUTION(分辨率)、CODECS(流的编码类型)、PROGRAM-ID(唯一 ID) |