什么是 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 等,以满足不同应用场景的需求。

下面是来自苹果官网的 编码和传送流媒体示意图

  1. 硬件编码器接收到音视频输入,将其编码为 HEVC 视频和 AC-3 音频;
  2. 服务端输出分段的 MPEG-4 文件或者 MPEG-2 传输流;
  3. 服务端的分段器(Stream Segmenter)同时会将流分割成一系列的短媒体文件,并将它放置在 Web 服务器上;
  4. 服务端的分段器还会创建和维护一个包含媒体文件列表的索引文件,索引文件的 URL 会被发布到 Web 服务器上;
  5. 客户端会按照顺序请求所有的媒体文件,并在各个端上都能不间断进行播放展示;

时序图大致如下:

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 播放列表的示例:

#EXTM3U
#EXTINF:123, Artist Name - Track Title
/path/to/music/file.mp3
#EXTINF:321, Another Artist Name - Another Track Title
http://example.com/path/to/another/music/file.mp3

M3U8

M3U 使用 Latin-1 字符集编码,而 M3U8 使用的是 UTF-8,所以它最后面的 8 是这么个意思。
因此如果文本使用本地系统的默认非 Unicode 编码(例如 Windows 代码页)进行编码,则该文件保存为 .m3u 文件扩展名;如果文本使用 UTF-8 编码,则保存为 .m3u8 扩展名。M3U 和 M3U8 都是苹果公司在 HLS 协议格式使用的基础。

下面我们通过一个小 demo 来实践了解下真实的 M3U8 长什么样子:

  1. 访问 30 Second Videos 下载一个 MP4 视频,假设你保存的文件叫 input.mp4
  2. 通过 ffmpeg.mp4 转成 .m3u8 文件(如果你未安装 ffmpeg 参考这里进行下载7,MAC 用户可以直接通过 brew install ffmpeg 进行安装);
ffmpeg -i input.mp4 -codec: copy -start_number 0 -hls_time 10 -hls_list_size 0 -f hls output.m3u8

这段含义解释如下:

  • -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
  1. 查看当前目录,会发现多了几个文件,.m3u8.ts
ls | grep output
output.m3u8
output0.ts
output1.ts
  1. 查看 .m3u8 文件内容;
cat output.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:12
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:12.160000,
output0.ts
#EXTINF:6.480000,
output1.ts
#EXT-X-ENDLIST
  1. 尝试播放 .m3u8 文件,看看效果;
ffplay -i output.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)

Footnotes

  1. HTTP Live Streaming - Wikipedia

  2. Moving Picture Experts Group - Wikipedia

  3. Joint Photographic Experts Group - Wikipedia

  4. Digital rights management - Wikipedia

  5. HEVC将会取代H.264的原因-CSDN博客 2

  6. M3U - Wikipedia

  7. Download FFmpeg