使用 VideoToolbox 探索低延迟视频编码 | WWDC 演讲实录

{"type":"doc","content":[{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文根据 Peikang 在 WWDC 2021 分享翻译,演讲者 Peikang,来自 Video Coding 和 Processing 团队。译者陶金亮,网易云信资深音视频开发工程师,拥有多年端侧音视频工作经验。","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/39/3934e03882e3e0a7ce34ad70a6d92c29.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"支持低延迟编码已成为视频应用程序开发过程的一个重要方面,在低延迟直播和 RTC 领域有着广泛的应用。本分享主要分享了 VideoToolbox(一个低级框架,提供对硬件编码器和解码器的直接访问, 它提供视频压缩和解压缩服务,以及存储在 CoreVideo 像素缓冲区中的光栅图像格式之间的转换)是如何支持低延迟 H.264 硬件编码,以最大限度地减少端到端延迟并实现新的性能水平,最终实现最佳实时通信和高质量视频播放。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"分享实录视频:","attrs":{}},{"type":"link","attrs":{"href":"https://developer.apple.com/videos/play/wwdc2021/10158","title":"","type":null},"content":[{"type":"text","text":"https://developer.apple.com/videos/play/wwdc2021/10158","attrs":{}}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"低延迟编码对于许多视频应用非常重要,尤其是实时视频通信应用。在本次演讲中,我将在 VideoToolbox 中介绍一种新的编码模式,以实现低延迟编码。这种新模式的目标是针对是实时视频通信应用优化现有的编码器流水线。那么实时视频通信应用需要什么?我们需要最大限度地减少通信中的端到端延迟。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/04/048833c421f211294241c0c6a5030f53.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们期望通过让视频应用程序与更多设备进行通信来增强互操作性。例如:当呼叫中有多个接收者时,编码器管道也应该是高效的,并且,该应用程序需要以最佳视觉质量来呈现视频。那么,我们需要一种可靠的机制来从网络丢失引入的错误中恢复通信。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我今天要讲的低延迟视频编码将在这些方面进行优化。使用","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"低延迟编码模式","attrs":{}},{"type":"text","text":",我们的实时应用程序可以达到新的性能水平。在本次演讲中,我将首先概述低延迟视频编码。我们可以对如何在管道中实现低延迟有基本的了解。然后我将展示如何使用 VTCompressionSession API 来构建管道并使用低延迟模式进行编码。最后,我将讨论我们在低延迟模式下引入的多个功能。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"低延迟视频编码","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/96/96e611c7db5315b490366d6bb7d2f367.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先让我概述一下低延迟视频编码。这是 Apple 平台上视频编码器管道的简图。 VideoToolbox 将 CVImagebuffer 作为输入图像,它要求视频编码器执行 H.264 等压缩算法以减少原始数据的大小。输出的压缩数据封装在 CMSampleBuffer 中,可以通过网络传输进行视频通信。从上图中我们可以注意到,端到端延迟可能受两个因素影响:处理时间和网络传输时间。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/29/29ad37abf1a6f5cbc3f2db682790b5b0.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"为了最大限度地减少处理时间,**低延迟模式消除了帧重新排序,遵循一进一出的编码模式。**此外,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"该低延迟编码模式下的速率控制器对网络变化的适应速度也更快","attrs":{}},{"type":"text","text":",因此也可以最大限度减少网络拥塞造成的延迟。通过这两个优化,我们已经可以看到与默认模式相比,已经有了明显的性能提升。**对于 720p 30fps 的视频,低延迟编码可以减少高达 100 毫秒的延迟。**这种节省对于视频会议至关重要。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通过这样的操作实现了减少延迟,我们可以为视频会议和直播等实时通信实现更高效的编码管道。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"此外,低延迟模式始终使用硬件加速视频编码器以节省电量。请注意,此模式支持的视频编解码器类型为 H.264,我们将在 iOS 和 macOS 上引入此功能。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/00/0039da1d6f72fb6a035709780efad89d.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"在 VideoToolbox 中使用低延迟模式","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下来,我想谈谈如何在 VideoToolbox 中使用低延迟模式。我将首先回顾 VTCompressionSession 的使用,然后向您展示启用低延迟编码所需的步骤。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"VTCompressionSession 的使用","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"当我们使用 VTCompressionSession 时,首先要使用 VTCompressionSessionCreate API 创建会话。并通过 VTSessionSetProperty API 配置会话,例如目标比特率。如果未提供配置,编码器将以默认行为运行。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"创建会话并正确配置后,我们可以通过调用 VTCompressionSessionEncodeFrame 将 CVImageBuffer 传递给会话,同时可以从会话创建期间提供的输出处理程序中检索编码结果。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在压缩会话中启用低延迟编码很容易,我们唯一需要做的就是在会话创建过程中进行修改,如下文的代码:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先,我们需要一个用于编码器规范的 CFMutableDictionary,编码器规范用于指定会话必须使用的特定视频编码器。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然后我们需要在 encoderSpecification 中设置 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"EnableLowLatencyRateControl","attrs":{}},{"type":"text","text":" 标志。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/39/399e44adbaa5012db0a1318486a482cb.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最后,我们将此 encoderSpecification 赋予 VTCompressionSessionCreate,压缩会话就将在低延迟模式下运行。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"配置步骤和往常一样。例如,我们可以使用 AverageBitRate 属性设置目标比特率。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"好的,我们已经介绍了 Video Toolbox 低延迟模式的基础知识。下面,我想继续介绍此模式中的新功能,它们可以进一步帮助我们开发实时视频应用程序。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"VideoToolbox 低延迟模式新功能","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"到目前为止,我们已经讨论了使用低延迟模式的延迟优势,其余的好处可以通过我将要介绍的功能来实现。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/b9/b9d1215d14dd65109cb572a886757634.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第一个功能是新的 Profiles,我们通过向管道添加两个新 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Profiles","attrs":{}},{"type":"text","text":"来增强互操作性。也会聊聊**时域分层SVC,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"此功能在视频会议中非常有用。也可以使用","attrs":{}},{"type":"text","text":"最大帧量化参数(Max QP)","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"对图像质量进行细粒度控制。最后,我们希望通过添加","attrs":{}},{"type":"text","text":"长期参考(LTR)**的支持来提高错误恢复能力。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"新的 Profiles 支持","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"让我们谈谈新的 Profiles 支持。 Profile 定义了一组解码器能够支持的编码算法,Profile 用于确定视频编码过程中帧间压缩使用的算法(例如是否包含 B 帧、CABAC 支持、颜色空间支持等),Profile 越高,就说明采用了越高级的压缩特性,对应的对编解码硬件的要求也越高。为了与接收方通信,编码比特流应符合解码器支持的特定配置文件。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/56/56b07119a76ff9faf696dd8a203cf694.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 VideoToolbox 中,我们支持一系列profiles,例如Baseline Profile、Main Profile和High Profile。今天,我们为该系列添加了两个新profiles:Constrained Baseline Profile (CBP) 和 Constrained High Profile (CHP) 。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"CBP 主要用于低成本应用,而 CHP 则具有更先进的算法以获得更好的压缩比。我们可以先检查解码器功能以判断应该使用哪个 Profile。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/14/144aa10ad282861cb8dce17ac47fc113.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"想要使用 CBP,只需将 ProfileLevel 会话属性设置为 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"ContrainedBaseLine_AutoLevel","attrs":{}},{"type":"text","text":"。同样,我们可以将Profile级别设置为 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"ContrainedHigh_AutoLevel","attrs":{}},{"type":"text","text":" 以使用 CHP。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"时域分层SVC","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"现在让我们谈谈时域分层 SVC。我们可以使用时域分层来提高多方视频通话的效率。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a8/a8a0def13bc5c456733134fd14f8e636.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"例如:一个简单的三方视频会议场景。在此模型中,接收器 A 的带宽较低,为 600kbps,而接收器 B 的带宽较高,为 1,000kbps。通常,发送端需要对两组码流进行编码,以满足每个接收端的下行带宽。这种做法可能不是最佳的。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"该模型可以通过时域分层 SVC 来更加高效的实现,其中发送方只需要编码一个比特流,但最后可以比特流输出可以分为两层。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们来看看这个过程是如何工作的。这是一个编码视频帧序列,其中每一帧都使用前一帧作为预测参考。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/c0/c02cbab9aef1c5e83b160c2e8907575d.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/05/056d5a4fd14087c5f982cb3c80ac9093.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们可以将一半的帧拉入另一层,我们可以更改参考,以便只有原始层中的帧用于预测。原始层称为基础层,新构建的层称为增强层。增强层可以作为基础层的补充,以提高帧率。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"对于接收器 A,我们可以发送基础层帧,因为基础层本身已经是可解码的。更重要的是,由于基础层只包含一半的帧,所以传输的数据速率会很低。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/52/5280648dc7548af764f607933cad8dc4.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"另一方面,接收器 B 可以享受更流畅的视频,因为它有足够的带宽来接收基本层帧和增强层帧。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们来看看使用时域分层 SVC 编码的视频。我将播放两个视频,一个来自基础层,另一个来自基础层和增强层。基础层本身可以正常播放,但同时我们可能会注意到视频不太流畅。如果我们播放第二个视频,我们可以立即看到差异。与左侧视频相比,右侧视频具有更高的帧速率,因为它同时包含基础层和增强层。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"左侧视频具有 50% 的输入帧率,并使用 60% 的目标比特率。这两个视频只需要编码器一次编码一个比特流。当我们进行多方视频会议时,这将更加节能。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ce/ce31feece019370a8c135ec77cd6fd2d.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"时域分层的另一个好处是错误恢复能力。我们可以看到,增强层中的帧不用于预测,因此对这些帧没有依赖性。这意味着如果在网络传输过程中丢失了一个或多个增强层帧,其他帧不会受到影响。这使得整个会话更加健壮。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/c6/c6c55ea560505848b31e0a404b89544a.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"启用时域分层的方法非常简单。我们在低延迟模式下创建了一个名为 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"BaseLayerFrameRateFraction","attrs":{}},{"type":"text","text":" 的新会话属性,只需将此属性设置为 0.5,这意味着一半的输入帧分配给基础层,其余分配给增强层。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们可以从示例缓冲区附件中检查图层信息。对于基础层帧,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"CMSampleAttachmentKey_ IsDependedOnByOthers","attrs":{}},{"type":"text","text":" 将为真,否则为假。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/1c/1ca6b779414e363ca2659fea9da670dd.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们还可以选择为每一层设置目标比特率。请记住,我们使用会话属性 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"AverageBitRate","attrs":{}},{"type":"text","text":" 来配置目标比特率。目标比特率配置完成后,我们可以设置新的 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"BaseLayerBitRateFraction","attrs":{}},{"type":"text","text":" 属性来控制基础层所需的目标比特率百分比。如果未设置此属性,则将使用默认值 0.6。我们建议基础层比特率分数应在 0.6 到 0.8 的范围内。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"最大帧 QP","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"现在,让我们看看最大帧量化参数或者说是最大帧 QP。帧 QP 用于调节图像质量和数据速率。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/87/875177e58a28f8eab0eb0382460bd479.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们可以使用低帧 QP 来生成高质量的图像。但在这种情况下,图像尺寸会很大。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/35/350127fb5a062d29cc794e926876efb7.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"另一方面,我们可以使用高帧 QP 来生成低质量但尺寸较小的图像。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a6/a6f1c0e3c6c7c816a719b5e04423bc11.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在低延迟模式下,编码器使用图像复杂度、输入帧速率、视频运动等因素调整帧 QP,以在当前目标比特率约束下产生最佳视觉质量。所以我们鼓励依靠编码器的默认行为来调整帧 QP。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但是在某些客户端对视频质量有特定要求的情况下,我们可以控制编码器使用最大帧 QP。使用最大帧 QP 时,编码器将始终选择小于此限制的帧 QP,因此客户端可以对图像质量进行细粒度的控制。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/0d/0da790678e0acb91f9d6b752bed1d439.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"值得一提的是,即使指定了最大帧 QP,常规速率控制仍然有效。如果编码器达到最大帧 QP 上限但比特率预算用完,它将开始丢弃帧以保持目标比特率。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用此功能的一个示例是通过较差的网络传输屏幕内容视频。我们可以通过牺牲帧速率来进行权衡,以发送清晰的屏幕内容图像,通过设置最大帧 QP 可以满足此要求。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/1e/1ecc55b3d4c21c93b485235f08ca2ae3.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们可以使用新的会话属性 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"MaxAllowedFrameQP","attrs":{}},{"type":"text","text":" 传递最大帧 QP。根据标准最大帧 QP 的值必须介于 1 到 51 之间。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"长期参考帧 (LTR)","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"说一下我们在低延迟模式下开发的最后一个功能,长期参考帧。长期参考帧即 LTR 可用于错误恢复。让我们看一下这张图,其中显示了管道中的编码器、发送方客户端和接收方客户端。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/68/687f45060c25228b42ff1abd0d9907d6.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"假设视频通信通过一个连接不良的网络,由于传输错误,可能会发生帧丢失。当接收方客户端检测到帧丢失时,它可以请求刷新帧以重置会话。如果编码器收到请求,通常它会编码一个关键帧以用于刷新目的,但关键帧通常相当大。大的关键帧需要更长的时间才能到达接收器。由于网络条件已经很差,大帧可能会加剧网络拥塞问题。那么,我们可以使用预测帧而不是关键帧进行刷新吗?答案是肯定的,如果我们有帧确认。让我们来看看它是如何工作的。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/b6/b62eab316807b9260df14a9bbdaa2035.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先,我们需要决定确认的帧。我们称这些帧为长期参考帧或 LTR,这是编码器的决定。当发送方客户端传输 LTR 帧时,还需要向接收方客户端请求确认。如果成功接收到 LTR 帧,则需要返回确认。一旦发送方客户端获得确认并将该信息传递给编码器,编码器就知道对方收到了哪些 LTR 帧。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ab/ab73495de32c50874115d9397e23770b.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"再来看看网络不好的情况:当编码器收到刷新请求时,因为这次,编码器有一堆已确认的 LTR,它能够对从这些已确认的 LTR 中的一个预测的帧进行编码,以这种方式编码的帧称为 LTR-P。与关键帧相比,LTR-P 的编码帧大小通常要小得多,因此更容易传输。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"现在,让我们谈谈 LTR 的 API。请注意,帧确认需要由应用层处理,它可以通过 RTP 控制协议中的 RPSI 消息等机制来完成。这里我们只关注编码器和发送方客户端在这个过程中是如何通信的。启用低延迟编码后,我们可以通过设置 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"EnableLTR","attrs":{}},{"type":"text","text":" 会话属性来启用此功能。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/c5/c56768f71b697f20d3693c60fb9afdba.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"当 LTR 帧被编码时,编码器将在示例附件 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"RequireLTRAcknowledgementToken","attrs":{}},{"type":"text","text":" 中用信号发送一个唯一的帧令牌。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/b5/b5850b4191ce8c299b2f9030096a3799.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"发送方客户端负责通过 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"AcknowledgedLTRTokens","attrs":{}},{"type":"text","text":" 帧属性将确认的 LTR 帧报告给编码器。由于一次可以收到多个确认,我们需要使用一个数组来存储这些帧标记。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/f1/f11d7e67c7d795385587ecff9072f4ec.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们可以随时通过 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"ForceLTRRefresh","attrs":{}},{"type":"text","text":" 框架属性请求刷新框架。一旦编码器收到这个请求,一个 LTR-P 将被编码。如果没有已确认的 LTR 可用,在这种情况下,编码器将生成一个关键帧。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"总结","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以上就是本次 Peikang 在 WWDC 2021 大会上分享的全部内容译文,若有翻译不合理处,欢迎指正交流。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"目前网易云信在客户端层面实现了软件编码的 SVC 和长期参考帧方案,同时服务器在转发上面也实现了 SVC 方案。SVC 提供了服务器一个额外的手段控制视频流的转发码率,再结合大小流和码率压制, 以及客户端下行的网络带宽探测和拥塞控制等手段,网易云信为了追求极致的观看体验,不断的打磨产品,本次分享的内容,我相信不久就可以在云信的产品中得到很好的运用。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"分享实录视频:","attrs":{}},{"type":"link","attrs":{"href":"https://developer.apple.com/videos/play/wwdc2021/10158","title":"","type":null},"content":[{"type":"text","text":"https://developer.apple.com/videos/play/wwdc2021/10158","attrs":{}}]}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章