HLS
Easy Tech
#013#
2009年,Apple推出了HLS(HTTP Live Streaming)——基于HTTP的自适应码率流媒体传输协议。HLS描述了一组通过互联网提供音视频服务的工具和程序。一个视频可以被分割成多个视频切片,这些切片的传送位置和顺序在一组被称为播放列表的XML文件中,该文件以文件扩展名m3u8结尾。人们可以使用兼容了HLS的播放器播放视频。
审校者注:原文说HLS使用了XML文件,是一个错误的说法,为了保留和原文一致,翻译并未去纠正这个错误,实际上,HLS 使用的是M3U8 文件,它是基于M3U扩展的UTF-8文本文件。
在本篇文章中,我们将深入了解实现HLS视频流的程序和工具。如果你对这一领域不太了解,可以先阅读什么是视频点播(VOD)?和理解ABR及其工作原理这两篇文章。
HLS的历史
2009年,Apple在推出iPhone 3时,同时推出了HLS。目的是提升iPhone用户的媒体传输体验,并且使用户不再遇到带宽波动和传输受到干扰等问题。从那时起,Apple便一直定期改进HLS,使它成为可靠、被广泛支持的视频传输协议。
Apple的网站上有大量相关文档,包括创作指南、HLS简介、HTTP实时流媒体等。你也可以参考相关规范,查看HLS的更多细节并对它有更多了解(其中有对各种标签的清晰解释,以及ABR视频流的详尽介绍)。
HLS的架构
HLS并不需要高级的硬件来传输视频,它是一个简单高效的协议。通过HLS,你可以使用常规的Web服务器存储和分发内容。但是它需要将数据存储在适当的格式中,且客户端软件能够获取并处理HLS视频内容。让我们一起来看看HLS视频传输服务的架构是什么样子。
HLS架构 (图片来自Apple)
编码器:该编码器可以生成H.264/AVC或者HEVC内容,并遵守Apple创作规范中指定的标准。这些指南非常全面且具体。比如,它们为每个所支持的编解码器指定容器格式。对于H.264来说,你必须使用fMP4或者TS(Transport Stream)。当你在创建自己的HLS流媒体服务器时,请务必阅读指南内容。
打包器(Packager):打包器获取视频后,将其切割成短的视频切片(如10秒长)。比如,一个小时的电影会被切割成360个10秒长的视频切片,然后创建一个被称为播放列表的文件,其中包含视频名字、位置以及切片播放序列(和描述编解码器、分辨率和码率等的元数据一起)。创建这些视频切片的过程被称为视频分片,或者更为人所熟知的打包。
Web服务器:是指被请求时任何能够提供文件的Web服务器。当客户端发起请求时,HLS服务器需要提供的文件是播放列表(m3u8文件),以及实际的A/V内容(TS切片或者 fMP4)。
播放器/客户端:任何理解HLS协议和能够播放HLS流媒体(音频和视频)的播放器。播放从下载播放列表开始,然后使用播放列表连续下载视频切片,再渲染到屏幕。
HLS播放列表示例
HLS播放列表有两种类型:主清单(master manifest)和子清单(child / media manifest)。让我们通过一个例子来理解它们是如何联系起来的。假设你已将一部电影以3个不同的分辨率进行编码:1080p、720p和480(也指表征,rendition)。在使用HLS协议封装后,你会得到1个主清单和3个子清单。
审校者注:最新的HLS RFC https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis-10 已经使用Multivariant Playlist 和 Media Playlist,原因是master/slave 被认为有负面的文化影响。2020年夏天,计算机行业对master/slave 这两个词的使用引起了人们的注意,在大量抗议活动和日益加剧的社会动荡中,这两个词被认为是不合时宜且过时的,这最终导致了这两个词出现各种中性的替代词。
主清单将描述视频不同部分的表征及其规范(包括音频和视频编解码器、语言和码率)。子清单将列出各个表征的所有视频切片(位置、名字和序列)。所以在这种情况下,你将得到3个子清单——分别是1080p、720p和480p。
下面是一个主清单示例,给出了构成编码和视频流阶梯(streaming ladder)的三种不同的表征信息。
#EXTM3U
#EXT-X-MEDIA:URI="subtitle/lang_en/subtitle_index.m3u8",TYPE=SUBTITLES,GROUP-ID="subtitles",LANGUAGE="en",NAME="English",DEFAULT=YES,AUTOSELECT=YES
#EXT-X-STREAM-INF:BANDWIDTH=893752,AVERAGE-BANDWIDTH=560289,RESOLUTION=854x480,CODECS="avc1.4D401F,mp4a.40.2",SUBTITLES="subtitles"
media-4/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1494976,AVERAGE-BANDWIDTH=891779,RESOLUTION=1280x720,CODECS="avc1.640028,mp4a.40.2",SUBTITLES="subtitles"
media-5/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=3262928,AVERAGE-BANDWIDTH=1894009,RESOLUTION=1920x1080,CODECS="avc1.640028,mp4a.40.2",SUBTITLES="subtitles"
media-6/index.m3u8
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=161304,RESOLUTION=854x480,CODECS="avc1.4D401F",URI="media-4/iframes.m3u8"
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=241392,RESOLUTION=1280x720,CODECS="avc1.640028",URI="media-5/iframes.m3u8"
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=532416,RESOLUTION=1920x1080,CODECS="avc1.640028",URI="media-6/iframes.m3u8"
下面给出了用于主清单的标签解释:
- EXT-X-STREAM-INF: 表示可用于电影播放的替代表征(alternative rendition)。
- EXT-X-I-FRAME-STREAM-INF: 表示仅I帧表征,用于快速搜索/快进快退模式,并在搜索时显示缩略图(至少包括流行用例中的两个)。
下面是子清单的一小段,属于主清单所指向的表征之一。
#EXTM3U
#EXT-X-VERSION:4
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-TARGETDURATION:4
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:4.000000,
segment-0.ts
#EXTINF:4.000000,
segment-1.ts
#EXTINF:4.000000,
segment-2.ts
#EXTINF:4.000000,
segment-3.ts
#EXTINF:4.000000,
segment-4.ts
HLS标签解释
下面是一些在m3u8文件中常见标签的解释:
- EXTM3U: 表示该文件是一个扩展的m3u文件。每个HLS播放列表必须以此标签开始。
- EXT-X-PLAYLIST-TYPE: 该标签取两个值(VOD或EVENT)中的任意一个。如果是VOD播放列表,那么服务器自始至终不能改变这个列表。如果是EVENT,服务器也不能改变或者删除该列表中已有内容,但是可以在后面追加内容。
- EXT-X-INDEPENDENT-SEGMENTS:该标签表示每个视频切片中的每一个媒体示例无需其他切片的信息就可以被解码。并适用于播放列表中的所有切片。
- EXT-X-TARGETDURATION: 指定媒体文件的最长持续时间(以秒为单位)。
- EXTINF:该标签指定媒体切片的持续时长。后面应该接续相关媒体切片的URI(必须如此)。你应该确保EXTINF的值小于或者等于它所指的媒体文件的实际时长。
HLS的最小切片时长是多少?
早些时候,Apple会推荐使用10秒切片时长(EXTINF)值来打包视频,但现在已经越来越少见。内容提供商越来越多地将切片时长减少到4秒和6秒,主要原因如下所示:
- 减少首屏延迟、加入时间、延迟:Apple在播放器端要求,播放开始前,必须缓冲3个视频切片。这么做又意味着什么呢?如果你以5 mbps的速度编码,那么每秒视频的“花费”5 Mbit。如果你已经打包的切片时长是10秒的视频,然后需要缓冲3个切片,这样即使在视频还没开始播放的情况下,你就需要去下载150 Mbit(5 mbps * 10 seconds * 3个视频切片)或者18.75MB的视频。
- 减少重新缓冲的影响:如果下载一个片段需要10秒,那么在这10秒内,网络条件可能发生很多变化。网络速度可能下降,这将导致播放器的缓冲区在下载视频时被耗尽,造成缓冲问题。使用较短的HLS片段在这种情况下更有意义,因为可以在更短的时间内获得得分片,让播放器有机会对网络条件做出更好的反应。
如何将TS视频打包进HLS格式?
商业打包器:在开源和商业领域中,HLS受到了广泛的打包支持。USP(Unified Streaming)和Wowza是我马上想到的支持HLS的两家公司,他们支持开箱即用的HLS的打包。
在开源方面,你可以使用Shaka packager和FFmpeg来将视频打包成HLS格式。
HLS的播放支持
播放器支持:作为广为流行的格式,HLS被大部分头部播放器公司和浏览器默认支持。我能想到的支持HLS的播放器公司包括CastLabs、Bitmovin、THEOPlayer、NexPlayer、Kaltura和JWPlayer等。支持HLS的开源播放器包括HLS.js和带有HLS.js插件的VideoJS。
以上提到的公司也为iOS/tvOS、Android等提供支持HLS播放的App。谷歌的Exoplayer也可以原生支持HLS播放。
浏览器支持:HLS播放在Safari中也获得了原生支持(这意味着你可以将HLS播放列表放到浏览器中,按下Enter键后,就可以直接播放视频,而不需要外部播放器)。但通常情况下,公司使用开源或者商业播放器(上文列出的那些)来播放HLS视频。
测试你的HLS播放列表?
要测试你的视频流,你可以使用参考 HLS.js播放器(https://hls-js.netlify.com/demo/)。你可以粘贴自己的URL上去,并检查是否符合参考的 HLS 播放器。确保你的视频流来自Https 链接,否则播放器会崩掉。或者,你可以关闭安全检测或使用 CORS 插件强制播放。下面是所呈现的页面:
你还可以使用Demo页底部的工具来分析视频流性能。
小 结
Hi,伙计们,今天就告一段落了。希望你们能够理解HLS协议的工作原理以及使用HLS传输视频时都需要什么。在后续的文章中,我会告诉你如何使用FFmpeg创建HLS视频流,并将其传输到全世界!