MoQ(Media Over QUIC) 取代 RTP 增强 HLS: 实现高质量、低延迟的流媒体传输
现如今,挺多互联网视频内容的传输方式大体分成两种:一种是经济高效但略显落后的HTTP Adaptive Streaming(以下简称HAS),另一种是基于 WebRTC 的视频传输,其响应速度超快,但基础设施成本高昂。这两种方法都兼顾了规模和速度,但往往以牺牲其中之一为代价。而一种新协议Media over QUIC(MoQ)通过弥合这些差距提供了一种可能的演进。
以HLS和 DASH 等协议为代表的 HAS 已成为互联网上视频传输的代名词。这种方法得益于 HTTP 的普及和随之发展起来的广泛的 CDN 基础设施,从而实现了可扩展且经济高效的分发。在另一端,WebRTC 适合实时通信,通常会牺牲一些质量来换取近乎即时的传输,这对于视频会议和交互式应用来说至关重要。事实证明,每种方法在各自的领域都很有用,但要满足日益增长的以低延迟传输高质量广播体验的需求,并做到经济高效,这两种方法都不容易适用。MoQ 提出了一种统一的方法,有可能同时提高质量和延迟,而无需专门的基础设施。
在采集和贡献方面,情况则更加多变。RTMP 一直是流媒体贡献的中坚力量,但人们希望降低直播工作流中的端到端延迟,因此迎来了替代方案。一些对延迟敏感的平台现在甚至可以通过新兴的 WHIP 信令标准,接受通过 WebRTC 提交的内容。
SRT 也因其低延迟功能而受到关注。然而,由于 Flash Player 的消亡使得 RTMP 不再是浏览器的直接交付协议,大多数贡献协议都需要额外的步骤才能与 HLS 或 DASH 等交付格式兼容。WebRTC 是一个明显的例外,因为所有主流浏览器都内置了 WebRTC 支持。但 WebRTC 并不适合所有的使用案例,即使是已经大规模使用 WebRTC 的地方,也在努力实现 WHIP 和 WHEP 的标准化,以便在浏览器之外创建广泛的生态系统支持。
MoQ 致力于简化整个流媒体流程,将贡献和分发再次整合到一个协议中,从而减少对中间转换的需求。由于 MoQ 仍处于早期开发阶段,要实现这一承诺尚需时日。
现代流媒体技术基础:从 TCP 和 UDP 到 HLS 和 RTP
在了解 MoQ 的具体功能之前,我们需要进一步了解当今主流流媒体传输协议的工作原理。
为简单起见,我们将重点讨论以下内容:
HLS:种广泛部署的 HTTP 自适应流媒体协议
RTP:WebRTC 媒体传输的核心协议
HLS 和 RTP 都堆叠在其他协议之上。这就是所谓的分层,它是一种强大的工具,多年来推动了许多技术创新。如果深入了解堆栈,你会发现我们在这里讨论的所有内容最终都有一个共同点,即它们都建立在互联网协议 (IP) 之上,而互联网协议又建立在某种形式的物理和数据链路层之上。我们的家中可能有 Wi-Fi 网络,我们正在观看的流媒体视频服务可能在其数据中心有光纤网络,但它们能够通过 IP 提供的寻址和路由功能相互通信。
UDP 和 TCP
在 IP 的上一层,我们可以看到两种主要的端口传输协议: UDP 和 TCP。
UDP 数据报本质上是原始 IP 数据包之上的一个非常薄的层。这意味着 UDP 协议本身并不能确保数据能一直传送到最终目的地。如果由于拥塞或随机链路丢失而导致数据报在途中丢失,UDP 层不会采取任何措施。
可以想象,大多数应用程序在尝试与远程主机通信时并不特别关心数据丢失,也不喜欢重新设计轮子来构建可靠的消息传递系统。TCP 的开发是为了提供解决此问题的通用解决方案,并且多年来已被证明非常有用。TCP 是面向连接的,从握手开始,确保可以进行双向通信并且另一端的主机已准备好接收数据。TCP 还确保发送的所有数据都得到另一端的确认,并限制主机之间传输的数据量,直到最近发送的数据的一定部分得到确认。
该系统在确保可靠传输数据方面效果很好,但它也有一些缺点。一个可能的问题是,等待确认可能意味着延迟发送数据,从而增加延迟。因此,一些需要以较低延迟传输媒体的系统放弃了 TCP 的可靠性,转而采用 UDP,在更高层构建自己的系统,以确保按时传输足够有用的数据。这是 RTP 做出的权衡,它是当今 WebRTC 为 Google Meet、Webex、Zoom、Discord 和其他实时视频会议应用程序提供视频和音频流的核心。
WebRTC
WebRTC 的设计目标是能够以各种方式容忍和处理丢失和拥塞,但要做到这一点,它必须承担相当多的责任和复杂性。WebRTC 有自己的拥塞控制算法,以及接收方请求编码器生成新关键帧的机制。在没有通用传输协议的支持的情况下解决这些问题的复杂性导致了一些问题。
大多数 WebRTC 实现都经过调整以支持视频会议用例,因此在出现拥塞和丢失时,往往会优先考虑低延迟。这可能表现为在遇到拥塞时出现间歇性跳过或偶尔出现短暂但有时剧烈的质量损失。如果你支持试图进行对话的人,那么这些可能是你想要做出的权衡,但如果尝试直播体育赛事或视频游戏流,这可能不是你想要的,因为观众希望获得相对较好的玻璃到玻璃延迟,但也希望保持一定的最低质量。如果这意味着始终及时获得更高比特率的帧,那么比实况动作再延迟半秒可能是可以接受的。当今实施的 WebRTC 往往不容易针对不同的用例重新平衡这些优先级。
虽然 WebRTC 可以在直接点对点模式下运行,但大多数有多名参与者的通话都受益于通过选择性转发单元 (SFU) 路由媒体,这样每个用户就不需要发送其音频和视频流的多个副本。住宅互联网连接的上行带宽通常比下行带宽少,因此,如果我加入有 20 名其他参与者的通话并想要分享我的视频,那么就有 20 个不同的视频流在竞争我有限的上行带宽。使用 SFU 大大简化了该过程,因为每个参与者都可以将其音频和视频发送到 SFU 一次,SFU 可以处理复制和中继这些流给所有其他参与者。因此,任何大规模运行的基于 WebRTC 的平台通常都需要 SFU。SFU 很有用,但与 HTTP 交付成本相比,相关成本可能相对较高。
HTTP Adaptive Streaming
HLS 和 DASH 是 HAS 的两个示例。它们通过 Web 本身所基于的 HTTP 协议传输媒体。HTTP 是一种应用层协议,最初设计用于访问文档。HTTP 位于 TCP 之上,以便能够利用其可靠的传输属性。HTTP 如今部署极为广泛,并且拥有许多独立的客户端(如 Chrome 或 Firefox)和服务器(如 Nginx 或 Apache)实现。内容分发网络 (CDN) 实现 HTTP 缓存反向代理服务器,以便能够从更近的位置透明地将内容分发给最终用户,从而降低成本并改善用户体验。因此,寻找通过 HTTP 传输视频的方法非常有意义。
通过 HTTP 传输视频的一种方法是将每个视频或电影托管为单个文件,然后发出单个 HTTP 请求来下载它,下载完成后,允许用户在 Web 浏览器中播放它。这在技术上是可行的,在 Web 视频发展的早期,有时就是这样做的。但这对用户来说并不是一个好的体验,而且如果用户甚至没有看完整个视频,就会有浪费大量带宽的风险。
如今,视频的编码和打包方式通常是以离散的块/部分/段(所有这些词在相关规范中都有具体的技术定义,但我们在此讨论的是 HAS 的一般做法)进行传输和播放。视频通常还以多种比特率进行编码,以便客户端可以根据可用带宽选择哪种比特率可以提供最佳体验。播放器通常使用单独的 HTTP 请求获取每个视频块,然后按顺序播放它们。
如果用户想要跳到视频中间并从那里开始播放,只需请求与视频那部分相对应的正确文件即可。这种流式传输方法是一项重大改进。相同的基本方法也有效,并且通常用于当今的流式传输现场活动。对于现场活动,当整体玻璃到玻璃延迟至关重要时,传统的基于 HTTP 的方法存在缺点。一个问题是,观众只能请求存在的对象,而服务器只能提供存在的对象。这意味着实况动作背后的整体延迟通常必须至少是我们最小的 HTTP 对象的大小。我们可以通过让这些对象跨越更短的时间来改进这一点,HLS 和 DASH 低延迟变体的最新改进就采用了这种方法。
由于底层传输协议的存在,还出现了一个额外的问题。由于 TCP 可以限制数据的发送,直到另一端确认收到了足够数量的最近发送的数据,因此当我们遇到网络拥塞时,我们已经发送的一些数据可能无法得到确认,因为这些数据可能被路由器丢弃,而路由器的队列太满,无法接受更多数据包。发生这种情况时,TCP 必须重新传输丢失的数据,以保证可靠的传输。这意味着我们必须等待更长的时间才能收到和确认这些重新传输的数据包。在我们等待的时候,拥塞可能已经清除,发送更多数据可能是安全的,但在收到远程对等方的确认之前,我们无法确定。一旦收到确认,我们就会恢复发送数据,但可能已经过去了一些时间。我们可能已经收到了对最新 HTTP 对象(最新视频块)的请求,但在发送该请求之前,我们必须先发送我们已经承诺要发送的所有其他内容。队列中的第一个块必须先发送,它会阻塞我们可能想要在其后发送的所有其他内容。这称为队头阻塞,这是 QUIC 旨在解决的问题之一。
进入 QUIC
与 TCP 一样,QUIC 支持有序且可靠的流传输。与 TCP 不同的是,QUIC 流不需要连接范围内的队头阻塞。这意味着,如果数据已准备好在新流上发送,则可以发送,即使其他流上已经有数据在传输中。QUIC 流创建起来很轻量,并且可以相对于同一连接内的其他流进行优先级排序。
QUIC 流也可以取消。QUIC 支持 QUIC 数据报,但由于这些功能,许多可能使用它们的情况也可以由 QUIC 流处理。QUIC 连接中的所有流和数据报共享一个拥塞控制器。这可以防止 QUIC 数据报不公平地淹没网络。
我们在 HTTP/1 和 HTTP/2 之下添加了 TLS 作为单独的层,现在称为“HTTPS”。虽然可以在没有 TLS 保护的情况下使用 HTTP,但出于多种原因,不再推荐这样做。在此图中,QUIC 位于 UDP 之上,与 TCP 和 TLS 提供的功能重叠。HTTP/3 显示为在 QUIC 之上运行的一种可能的应用层协议。虽然 Google 开发原始版本的 QUIC (gQUIC) 时考虑了 HTTP/3,但它经过数年的发展成为了 IETF QUIC 的标准化版本,而且很明显许多其他应用协议都可以利用 QUIC 的新功能。
QUIC 引入了许多新功能,并且在某些方面,它兼具了 TCP 和 UDP 的优点,同时还内置了 TLS 1.3。
QUIC 加密不仅可以保护用户流量免遭检查和篡改,还可以防止协议僵化,因为中间件更难推断出有关 QUIC 有效负载的任何信息,这些信息可用于定制中间件行为,从而使得将来难以改变 QUIC 的线路图像。
虽然 QUIC 在功能上是一个完整的传输协议,但它是在 UDP 的基础上运行的,因此无需更新已能传输 UDP 流量的中间件即可部署 QUIC。这也使得 QUIC 可以在用户空间中实现,与需要修改内核代码才能更新的网络协议相比,QUIC 的开发周期更快。QUIC 最终很可能会进入内核,甚至硬件加速网络堆栈,但选择从用户空间开始实验,应能更快地开发出新的协议功能。
QUIC 与 TLS 1.3 的深度集成意味着可以更快地完成握手,从而节省启动连接时的一些往返次数,缩短首字节时间 (TTFB) 并因此缩短首帧时间 (TTFF),这些是支持视频播放启动时良好体验质量的重要指标。虽然 QUIC 通过 TLS 1.3 提供内置加密,但需要注意的是,HTTPS 和 WebRTC 的 SRTP 等广泛使用的协议中已经存在类似的加密标准,因此在当今的流媒体环境中,加密和未加密选项之间的性能比较不再那么重要。
借助 HTTP/3,其中一些功能得以发挥作用,将 DASH 和 HLS 等基于 HTTP 的协议切换到 QUIC 可以提供优于 TCP 的性能。但是,为了充分利用 QUIC 的超低延迟交付功能,我们需要另一种协议来将这些功能公开给媒体感知应用层。这就是 Media over QUIC 工作组正在设计的。
Media over QUIC(MoQ)
Media over QUIC 是一组协议,目前由互联网工程任务组 (IETF) 的一个工作组正在开发,旨在为媒体的采集和分发提供简单的低延迟媒体传输解决方案。按照目前的规定,MoQ 实际上分为两个不同的协议层:通用的 Media over QUIC Transport (MoQT) 层和更具体的流格式。MoQT 协议旨在由中继 (即 CDN 容量) 实现,而这些中继不需要知道有关媒体有效负载的任何详细信息。在 MoQT 层,数据被组织成对象,这些对象具有标头,指示这些对象如何组成组和轨道。
MoQT 对象(MoQT Objects)是 MoQT 中最小的传送单位,它们可以通过缓存重新提供。MoQT Track是 MoQT 订阅者可以订阅的内容,订阅后,上游 MoQT 发布者将不断向订阅者推送属于该跟踪的 MoQT 对象。MoQT 组由一个或多个对象组成。一个新的 MoQT 组的起始点是订阅者可以加入轨道并有足够信息使用其接收到的对象的点。MoQT 还(目前)定义了几种不同的模式,用于说明如何将对象和组映射到 QUIC 流。
重要的是要记住,在 MoQT 层,这些都是非常通用的结构。你可能已经开始了解它们如何有效地应用于视频和音频流,但事实上,MoQT 可用于传输任何类型的媒体,甚至是纯文本。
MoQ 流媒体格式
在 MoQT 的基础上,我们还有各种流格式,它们描述了某种目录的格式,以及特定媒体类型与 MoQT 轨道、组和对象的映射。除了主要的 MoQT 草案外,我们目前还有基于 CMAF 的流格式草案 WARP(Without Any Published Expansion)、支持 RTC 用例的低开销媒体容器 (LOC) 格式的流媒体格式,以及基于 MoQT 的文本聊天草案,以帮助提醒我们保持 MoQT 层的相对通用性。
举个具体的例子,假设我们想使用类似 WARP 的流媒体格式流式传输视频。我们的视频采用 H.264 编码,每组图片(GoP)大小为 1 秒。这意味着我们每秒有一个 IDR 帧(或关键帧),然后在下一个 IDR 帧之前有 23 个三角编码的 P 帧。我们可以将 H.264 比特流打包到 MP4(ISO BMFF)容器中,这样每一帧视频都有一个新片段。
然后,我们可以获取这个碎片化的 MP4 (fMP4) 并通过 MoQ 提供它。首先,我们将创建一个 JSON 目录,描述媒体并告诉订阅者要订阅什么轨道名称才能接收我们的视频。然后,我们发布目录轨道以及我们的视频轨道,让订阅者可以访问它们。
目录轨道很简单,而且由于我们只公开单个 VOD 资产,因此不需要任何增量更新。我们可以将 JSON 目录放入目录轨道中第一个且唯一的组中的第一个且唯一的对象中。
在视频轨道上,我们可以做一些更有趣的事情。我们可以将每个片段放入其自己的对象中,并且每次获得新的关键帧时都可以启动一个新的组。我们还可以使用一种交付模式,确保将每个 MoQT 组放在新的 QUIC 流上。这样,我们将始终按照符合编解码器依赖性要求的顺序交付帧。由于我们的增量编码 P 帧依赖于它们之前的 I 帧(关键帧),我们可以将它们放入同一个组中,并知道播放器将始终在依赖于它们的任何 P 帧之前收到必要的 I 帧。
对于我们简单的 VOD 示例,我们可能会看到以这种方式传递媒体的一些优势,但它真正闪耀的地方是实时内容,特别是在低延迟很重要的时候。
对于直播内容,我们可能会选择使用 MoQ 从底层 QUIC 层提供的另一个功能:优先级。QUIC 允许发送者为流分配不同的优先级,以便在出现拥塞时,当有数据可供多个流发送时,最重要的数据将首先发送。MoQ 公开了这一点,以便我们可以将最近生成的组的优先级高于之前的任何组。如果出现拥塞,玩家将尽快获得最新的 GoP,以防他们想跳到直播边缘。
一个简单的 HLS 直播流的示例。在这里,我们可以看到客户端请求流的清单,几层 CDN 代理服务器从源检索该清单。清单描述了媒体并列出了客户端需要获取的实际视频文件。然后,客户端开始从最近的 CDN 请求这些视频文件。CDN 服务器可能需要返回源,或者它们可能已经缓存了这些文件。无论哪种方式,客户端都会对视频流的每个部分发出请求。
然后,在直播的情况下,客户端可能还需要轮询清单以获取更新,以便知道接下来应该获取哪些新制作的视频文件。这里的一切都是由客户端驱动的,观看直播涉及大量轮询。
让我们将其与一个简单的 MoQ 流示例进行比较。在这里我们可以看到 MoQ 协议如何由控制消息和对象(数据)组成。我们还可以注意到,一旦客户端进行了订阅,该轨道的所有未来对象都将发送给客户端,而无需单独请求。
目录对媒体的描述方式与清单类似,但不需要以相同的方式进行轮询,因为它们不需要枚举客户端要请求的每个对象。此外,如果目录有更新,它们也可以在可用时立即推送到客户端,因为目录本身就是客户端订阅的轨道。与当今 CDN 的 HTTP 代理服务器一样,MoQ 中继通过充当扇出节点并可选地缓存内容来分散负载。
MoQT 规范草案目前支持两种底层传输:QUIC 和 WebTransport。WebTransport 是一种新的协议和 Web API,在某些方面类似于 WebSockets,但用于 QUIC 而不是 TCP。这使我们能够在浏览器应用程序环境中利用 QUIC 的流复用和优先级功能。它涉及 HTTP/3,因为它首先发出特定的 HTTP/3 CONNECT 请求,类似于 WebSockets 发出带有 Upgrade: 标头的 HTTP 请求。此外,与 WebSockets 一样,一旦建立了 WebTransport 会话,它就不会使用 HTTP 请求和响应来传输数据。同样,与 WebSockets 类似,WebTransport 不一定是 HTTP 代理仅凭支持 HTTP/3 就支持中继的协议。
WebTransport 的价值在于它提供了一种从基于浏览器的应用程序直接访问 QUIC 提供的多路复用流传输的机制。
这意味着播放器和发布者都可以是原生 Web 应用程序。通过结合 WebTransport 和 WebCodecs(另一个相对较新的浏览器 API),开发人员可以对媒体的编码、交付和解码方式进行大量控制,从而将该领域的创新与浏览器本身原生实现每个功能的需求分离开来(就像 WebRTC 一样)。
简而言之,MoQ 背后的思路是将 HAS 协议的一些可扩展性特性与 WebRTC 等实时语音和视频协议的延迟特性融合在一起。