HLS是什么意思?
HLS(HTTP Live Streaming)是一种直播流协议,它利用当前广泛使用的 HTTP 技术为广大观众提供实时视频+音频体验。
它最初由 Apple 于 2009 年开发,现已在从台式机、移动电话到智能电视等设备中得到广泛采用。iPhone 推动了其最初的采用,并且在移动领域拥有重要的市场份额,其默认支持的 HLS 是一个极好的助推器。
了解 HLS 工作原理
让我们从高层次来了解HLS是如何工作的。从客户端(任何网络播放器)的角度来看,这些是其理解和播放媒体的步骤:
- 客户端向服务器发出 GET 请求以获取主播放列表。
- 客户端根据用户的网络条件从列表中选择最佳比特率。
- 接下来,它发出 GET 请求以获取与该比特率对应的播放列表。
- 它理解播放列表,开始获取不同的媒体片段,然后开始播放。
- 它循环重复最后两个步骤。
这是客户如何使用HLS的一个粗略计划。现在我们来看看这些播放列表/片段的具体内容。为了生成这些数据,我将使用媒体相关的瑞士军刀:ffmpeg。
让我们使用一个简单的命令创建一个示例视频:
ffmpeg -f lavfi -i testsrc -t 30 -pix_fmt yuv420p testsrc.mp4
这样就创建了一个时长为30秒的样本视频。
现在我们通过以下命令创建一个HLS播放列表:
ffmpeg -i testsrc.mp4 -c:v copy -c:a copy -f hls -hls_segment_filename data%02d.ts index.m3u8
这将在同一目录中创建一个播放列表,其中包含文件:
- index.m3u8
- data00.ts
- data01.ts
- data02.ts
不知道它们是什么?让我们来了解一下该命令的作用以及这些文件的含义。
我们首先分解命令。
我们用 -i 告诉 ffmpeg 将 MP4 视频作为输入,注意这也可以直接接受 RTMP 输入;只需要说类似这样的话:
ffmpeg -listen 1 -i rtmp://127.0.0.1:1938/live -c:v copy -c:a copy -f hls -hls_segment_filename data%02d.ts index.m3u8
这是另一个令人兴奋的方面,我们将在本文中进一步讨论。
接下来,理解-c:v copy
和-c:a copy
。这是一种将编码等音频/视频数据从源输入复制到输出的方式。您也可以在这里以不同的格式进行编码。例如,例如,如果您想在HLS播放列表中使用多种质量。
-f
告诉ffmpeg
我们的输出格式是什么,在本例中是 HLS。
-hls_segment_filename
告诉ffmpeg
我们想要的片段文件名的格式。
最后一个参数是我们的主播放列表的名称。
现在,开始处理文件:
在编辑器中打开主播放列表,如下所示:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.000000,
data00.ts
#EXTINF:10.000000,
data01.ts
#EXTINF:10.000000,
data02.ts
#EXT-X-ENDLIST
让我们理解下这些标签:
EXTM3U
:M3U(MP3 URL 或全称动态图像专家组音频第 3 层统一资源定位符)是多媒体播放列表格式名称,这一行表明我们正在使用扩展的 M3U 格式,根据 HLS 规范:“它必须是第一行每个媒体播放列表和每个主播放列表。”EXT-X-VERSION
:此标签指示我们的播放列表文件的兼容版本,播放列表格式已经不止一次迭代,并且有旧客户端不理解新版本,因此对于任何服务器生成的播放列表格式版本都必须发送此标签大于 1。它出现多次会导致客户端拒绝整个播放列表。- 这些是
Basic Tags
规范所指定的。 - 我们现在将继续讨论称为
Media Playlist Tags
. 其中第一个是EXT-X-TARGETDURATION
。这是一个必需的标志,再次告诉客户端它可以期望的最长段长度是多少。它的值以秒为单位。 EXT-X-MEDIA-SEQUENCE
:此标签提及第一媒体片段的数量。它是不必要的,默认情况下,如果不存在,则将其视为 0。它唯一的限制是它应该出现在第一个媒体片段之前。EXTINF
:此标签位于Media Segment Tags
并指示每个媒体片段的持续时间和元数据。根据规范,其格式为:<duration>, [<title>]
. 使用版本 3 以上的任何格式时,都需要以浮点数指定持续时间。标题主要是人类的元数据并且是可选的,ffmpeg
似乎默认情况下跳过了它。- 之后的每一行
EXTINF
指定在哪里找到媒体段。在我们的例子中,它们位于同一个文件夹中,因此它们被直接列出,但它们也可以位于子文件夹480p
中,例如 ,这意味着它们的名称为:480p/data01.ts
。请注意,这data01
也是我们在上面的命令中给出的一种格式,并且可以很容易地更改它。 EXT-X-ENDLIST
:我猜最难理解的标签是什么?人们绝对无法通过观察并说出它的作用。抛开笑话不谈,除了指示列表已结束之外,一个令人兴奋的属性是它可以出现在播放列表文件中的任何位置。如果手动构建这些文件,您可能需要小心地将其放置在正确的位置。
对于敏锐的读者来说,他们可能已经注意到这里没有列出多种比特率。好吧,我想首先用一个简单的例子来解释基本结构。
为了理解 ABR,让我们使用一个已经托管的 URL,例如:https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8
下载播放列表时,它看起来像这样:
#EXTM3U
#EXT-X-VERSION:1
## Created with Unified Streaming Platform (version=1.11.20-26889)
# variants
#EXT-X-STREAM-INF:BANDWIDTH=493000,CODECS="mp4a.40.2,avc1.66.30",RESOLUTION=224x100,FRAME-RATE=24
tears-of-steel-audio_eng=64008-video_eng=401000.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=932000,CODECS="mp4a.40.2,avc1.66.30",RESOLUTION=448x200,FRAME-RATE=24
tears-of-steel-audio_eng=128002-video_eng=751000.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1197000,CODECS="mp4a.40.2,avc1.77.31",RESOLUTION=784x350,FRAME-RATE=24
tears-of-steel-audio_eng=128002-video_eng=1001000.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1727000,CODECS="mp4a.40.2,avc1.100.40",RESOLUTION=1680x750,FRAME-RATE=24,VIDEO-RANGE=SDR
tears-of-steel-audio_eng=128002-video_eng=1501000.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2468000,CODECS="mp4a.40.2,avc1.100.40",RESOLUTION=1680x750,FRAME-RATE=24,VIDEO-RANGE=SDR
tears-of-steel-audio_eng=128002-video_eng=2200000.m3u8
# variants
#EXT-X-STREAM-INF:BANDWIDTH=68000,CODECS="mp4a.40.2"
tears-of-steel-audio_eng=64008.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=136000,CODECS="mp4a.40.2"
tears-of-steel-audio_eng=128002.m3u8
在这里,我们看到一个新标签EXT-X-STREAM-INF
。此标签提供有关给定流可用的所有变体的更多信息。该标签后面是任意数量的属性。
BANDWIDTH
:这是一个强制属性,其值告诉我们该变体每秒将发送多少位。CODECS
:这是另一个强制属性,分别指定视频和音频的编解码器。RESOLUTION
:这是一个可选属性,提及变体的像素分辨率。VIDEO-RANGE
:我们可以忽略这个标签,因为它没有在规范中指定,尽管在撰写本文时,hls.js 上有一个未解决的问题来添加对它的支持。SUBTITLES
:它是一个可选属性,指定为带引号的字符串。GROUP-ID
它必须与标签上的属性值匹配EXT-X-MEDIA
。这个标签也应该有SUBTITLES
它的TYPE
属性。CLOSED-CAPTIONS
:它是一个可选属性,与 大部分相同SUBTITLES
。它的区别有两点:- 它的属性值可以是带引号的字符串或
NONE
. EXT-X-MEDIA
隐藏式字幕的标记值应为CLOSED-CAPTIONS
。
- 它的属性值可以是带引号的字符串或
这些stream-inf标签后面的行指定在哪里可以找到相应的变体流,这是一个与我们之前看到的类似的播放列表。
RTMP 输入
之前,我们看到了一个 RTMP 输入ffmpeg
命令。它帮助我们了解现场 HLS 播放列表的另一个属性。重新审视该命令,它看起来像这样:
ffmpeg -listen 1 -i rtmp://127.0.0.1:1938/live -c:v copy -c:a copy -f hls -hls_segment_filename data%02d.ts index.m3u8
该命令应该给出类似于下面的输出,这似乎被卡住了。
现在,让我们来满足您成为流媒体的梦想!我们可以使用任何 RTMP 源,甚至是 ffmpeg,但在我们的演示中,我们将使用 OBS 发送数据到我们的 ffmpeg服务器监听 RTMP 输入。我在其中创建了一个简单的屏幕共享捕获输入,然后导航到设置中的流部分,在这里你会看到类似这样的屏幕:
将服务填写为自定义,并 rtmp://12.0.0.1:1938/live
使用空的流密钥添加服务器。现在单击应用并按OK
。
我们将登陆OBS的默认视图:
当我们点击 Start Streaming
时,我们将流媒体传输到本地 RTMP-to-HLS 服务器。您会注意到运行ffmpeg命令的文件夹。有新的文件名:
- index.m3u8
- data files with template
data{0-9}{0-9}.ts
让我们检查一下index.m3u8,我捕捉到的结果是:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:4
#EXT-X-MEDIA-SEQUENCE:3
#EXTINF:4.167000,
data03.ts
#EXTINF:4.167000,
data04.ts
#EXTINF:4.166000,
data05.ts
#EXTINF:4.167000,
data06.ts
#EXTINF:4.167000,
data07.ts
注意到没有结束播放列表标签了吗?这是因为这是一个实时播放列表,随着时间的推移不断变化,出现新的片段。例如,一段时间后,我的本地播放列表看起来像这样:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:4
#EXT-X-MEDIA-SEQUENCE:9
#EXTINF:4.167000,
data09.ts
#EXTINF:4.167000,
data10.ts
#EXTINF:4.166000,
data11.ts
#EXTINF:4.167000,
data12.ts
#EXTINF:0.640667,
data13.ts
#EXT-X-ENDLIST
旧的片段将被新的片段所取代。这有助于在直播活动时提供最新数据。
这在一定程度上涵盖了播放列表。现在让我们来谈谈片段文件。
容器格式
媒体段使用容器格式存储实际编码的视频/音频数据。详细讨论容器格式不在本文讨论范围之内。
HLS最初只支持MPEG-2 TS容器。这个决定不同于其他基于HTTP协议的容器格式。例如,DASH一直使用fMP4(碎片化MP4)。虽然最后苹果宣布在HLS中支持fMP4,但现在它已经正式被规范所支持。
媒体段大小
媒体段大小没有定义。通常情况下,媒体段的大小为10秒左右,但规范的另一部分规定了媒体段的大小。根据规范,必须获取并准备好至少三个片段才能开始播放。这意味着对于10秒的片段,在客户端开始播放之前需要加载30秒的缓冲区。我们可以根据需要随时更改,这也是我们在减少延迟时常用的调整参数。
组件明细
- 采集:采集(相关性相对较低)标志着我们的系统从用户那里获取输入的点,这可以通过不同的协议以各种格式完成,但像 Twitch 和 Youtube 这样的平台已经普及了 RTMP。然而,随着 OBS 中 WebRTC 的引入,这种情况似乎正在发生变化,使得使用 WHIP 以更低的延迟更快地提取内容成为可能。
- 处理:媒体处理包括转码、转复用等,具体取决于所使用的摄取格式。此处的输入将转换为在播放列表中索引的 MPEG-TS 或 fMP4 片段并准备好使用。
- 交付:交付是确保 HLS 可扩展性的一个重要方面。Web 服务器托管播放列表和片段,然后通过 CDN 发送给最终用户。CDN 会缓存这些 GET 请求,并进行自我扩展以返回静态数据,从而在流量更高的情况下请求时使协议具有高度可扩展性。
- 播放:流畅的播放对于良好的用户端体验至关重要。ABR 必须在播放器端充分实施,以便用户在流媒体期间体验到最小的体验下降。
HLS 提供的功能
- 通过通用格式 HTTP 进行分发,使其可以在任何地方轻松访问
- 使用 HTTP,HLS 可以利用底层 TCP 实现的优势,使重传处理开箱即用。
- 互联网的大部分内容都依赖于 HTTP,因此可以在所有消费设备上自动传送。
- 这对于基于 UDP 的协议(例如 RTP)来说变得具有挑战性,这些协议有时需要 NAT 遍历之类的东西才能正常工作。
- 轻松的 CDN 级缓存
- 扩展 HLS 变得非常容易,因为缓存 HTTP 得到了广泛支持,并且将其卸载到良好的 CDN 可以将源服务器上的负载降至最低,同时确保向所有消费者提供相同的音频 + 视频数据。
- 自适应比特率流式传输 (ABR)
- HLS 支持 ABR,因此互联网连接较差的用户可以快速切换到较低的比特率并继续享受流媒体。
- 内置广告插入支持
- HLS 提供易于使用的标签,可在流中动态插入广告。
- 隐藏式字幕
- 它还支持嵌入的隐藏式字幕,甚至 DRM 内容。
- 使用 fMP4
- 使用分段 MP4 有助于降低编码和交付成本,并提高与 MPEG-DASH 的兼容性。
HLS 的缺点
- HLS 以其极高的延迟而闻名。使其稍微好一点的简单方法之一是微调分段大小,然后将摄取协议更改为延迟较低的协议,例如 RTMP。但对于清晰的现场体验来说,普通的 HLS 还不够。计算界提供了社区 LL-HLS 和 Apple LL-HLS 作为解决方案。两者都有自己解决问题的方法,并且可以保证一些不错的延迟。
- HLS 规范指定客户端在启动之前至少需要加载三个段。现在,假设您将段大小设置为 10 秒。您已经看到流从一开始就有 30 秒的延迟。这也使得调整段大小非常重要。
最后的想法
拥有开放标准有助于采用和增长,同时使开放和封闭软件/硬件堆栈之间的互操作变得更加容易。HLS 在直播领域也发挥着同样的作用——它被广泛采用、简单而强大。它并没有尝试从头开始重新发明轮子,而是采用了当前广泛接受的协议并在此基础上构建。
作者:Fenil Jain
编译自dyte.io
本文来自作者投稿,版权归原作者所有。如需转载,请注明出处:https://www.nxrte.com/jishu/yinshipin/28911.html