WebRTC和NDI=广播公司天堂?

2020-07-19 10:51:33

在过去的几个月里,我们一直生活在这场流行病中,迫使许多人和公司改变了他们的日常模式。我们中的大多数人都被迫长时间呆在家里工作。这显然对整个广播业产生了影响。例如,想想新闻或脱口秀节目中的采访或任何形式的现场互动:没有能力招待客人(甚至经常是主持人!)。在制片厂,制作团队被迫寻找解决方案,让他们仍然能够做好自己的工作。

对于我们这些从事实时业务的人来说,这似乎是一个相对直截了当的答案。在实践中,这真的不是那么容易,大多数来自制作团队如何实际处理他们需要编辑和广播的流,以及他们使用的工具。正如经常发生的那样,我实际上受到了我们每天在Twitter上互动的聪明人的启发。尤其是来自Nimble Ape的丹·詹金斯(也是令人惊叹的CommCon活动的幕后策划者,请务必观看刚刚结束的最新虚拟版!)。我做了一个与BBC新闻相关的有趣的观察,山姆·马钦的回答对我很有启发性,因为它引入了一个我不知道的新“玩家”:

Skype仍然很受欢迎,因为它有一个NDI插件,可以让它在视觉混音器中看起来像是摄像机信号源,我还没有找到其他任何提供这种功能的公司。

-Sam Machin(@sammachin)2020年4月24日。

这是我第一次听说NDI,这是一种启示:它提醒我,一些选择往往是由他们继续使用现有工作流程的容易程度驱动的。这激起了我的兴趣,并让我为这场讨论做出了贡献,我想知道这场讨论有多容易(或多难!)。它可以执行某种类型的RTP到NDI转换:

我没有意识到NDI,我必须检查一下生成这样的流/设备有多容易:在Janus中,我们有一种方法可以将WebRTC流转换为普通的RTP流,以便在其他地方使用,所以也许有一种方法可以实现RTP到NDI。

-Lorenzo Miniero(@elMiniero)2020年4月24日。

提到OBS也很有趣,因为我们在Cosmo Software的朋友确实实现了一个能够与WebRTC交谈的OBS版本。不幸的是,这被证明是在转移注意力,因为正如Alex博士澄清的那样,OBS-WebRTC不支持WebRTC输入,而WebRTC输入本来可以帮助将传入的流从那里转换为NDI:

OBS中的NDI插件既有进也有出。在OBS-Studio-WebRTC中,我们只做原生WebRTC输出,因为WebRTC In Case由浏览器源功能负责(他们在内部使用CEF)。

-亚历克斯医生。Gouaillard(@agouaillard)2020年5月8日。

在这些交流之后,我真的很想把NDI作为一种技术来研究(特别是考虑到我对它一无所知),但后来生活和工作阻碍了我,我把它忘了。

然而,几周前,与丹的一次私人聊天再次引发了这种兴趣。他提到,他认识的一家视频制作公司真的很难从互联网上获得适当的实况转播,以便在他们每天制作的内容中使用。再一次,NDI被认为几乎是该行业的标准事实,而引入WebRTC流的适当方式仍然严重缺乏,这迫使编辑基本上以“老套”的方式捕获源材料。

因此,我决定开始研究NDI,以弄清楚我想知道的RTP到NDI转换是否确实可行。

网络设备接口(NDI)是NewTek开发的免版税软件标准,使视频兼容产品能够以帧准确且适合在现场生产环境中切换的高质量、低延迟方式通信、传送和接收广播质量的视频。

简而言之(可能会过度简化),它允许在同一LAN内实时交换多通道和未压缩的媒体流,利用mDNS进行服务发现。这允许制作人在同一LAN中使用来自不同来源的媒体,即不限于物理连接到其设置的设备。下面的图片(来自他们的宣传材料)从视觉角度使整个过程更加清晰。

显然,这项技术背后真正的优势在于它们提供的免版税SDK,以及可以实际与NDI媒体交互的广泛工具集:一旦流可用,无论其来源如何,都可以很容易地进行剪切/操作/处理,以便将其嵌入到更复杂的生产环境中。正因为如此,NDI实际上在许多媒体制作公司中得到了非常广泛的部署。

这就引出了一个关键问题:如果这也是远程采访的制作方式,制片人很可能会尝试使用任何让他们很容易获得可以直接使用的NDI来源的方式。显然,WebRTC对他们来说仍然很难使用:没有一种直接拉入WebRTC提要的方法,他们基本上被迫使用变通方法,比如捕获浏览器窗口,渲染远程视频,使用NDI录像机裁剪他们需要的内容,并以这种方式注入结果;对于音频,这可能意味着记录系统输出或类似的黑客攻击。

不用说,这是一个不太理想的解决方案,需要的工作比应该做的多:此外,如果呈现流的网页具有可以移动您感兴趣的部分的动态界面,甚至是有限的功能(例如,没有屏幕共享支持),那么它可能会更具挑战性。(=。这就是为什么我开始寻找将RTP或多或少直接转换为NDI的方法,以便使整个过程更容易使用。

我检查的第一件事是是否已经有一些RTP/NDI实现可用,答案是肯定的和否定的。我发现的第一个项目是一个开源插件,名为gst-plugin-ndi:这个项目非常有趣,但不幸的是只涉及NDI接收,而不是交付。正如我稍后将解释的那样,事实证明,这对验证我的努力仍然很有帮助,但这并不是我想要的。对任何FFmpeg集成的快速研究让我看到了这张票,它解释了FFmpeg在一段时间之前是如何确实支持NDI的,但在Newtek的版权侵权问题之后完全放弃了它。因此,也不是一个选择。

那么,下一步就是研究自己生成NDI内容的方法,幸运的是,这相当简单。事实上,NDI SDK是免版税的,可以在他们的网站上免费下载(链接会发送到您提供的邮件地址)。下载SDK后,您就可以访问很好的文档和大量示例。我看了一些演示如何发送音频和视频的示例,它们看起来很简单:事实上,对于视频,NDI需要几种不同支持格式的未压缩帧,而对于音频,未压缩帧可以是16pp或fltp(他们喜欢的浮点格式)。

考虑到WebRTC媒体的性质,我决定编写一个小型RTP接收器应用程序(称为rtp2ndi,极富创意),然后可以将音频和视频包解包并解码为NDI喜欢的格式:更具体地说,我使用libopus解码音频包,使用libavcodec解码视频(为简单起见,仅限于VP8)。至于NDI格式,我选择了用于视频帧的UYVY和用于音频的48 kHz 16pp(虽然Fltp是首选格式,但NDI SDK无论如何仍然支持)。

对于前者,我使用了我经常用于测试目的的许多流脚本中的一个,特别是一个简单的GStreamer管道,它通过预先录制的文件并通过RTP发送它。对于后者,我使用了上面提到的gst-plugin-ndi项目,它为我提供了一种在窗口中呈现传入提要的简单方法。

因此,我首先启动我的rtp2ndi工具,将其绑定到两个端口以接收RTP数据包,并指定用于NDI流的名称:

RTP接收器就位后,我启动脚本向其提供数据包:

这导致我的RTP接收器按照预期开始接收和解码数据包,并在此过程中将其转换为NDI:

此时,我所要做的就是启动GStreamer管道来实际接收NDI流并显示它:

在这一点上,我有了一个很好的起点,所以下一步是尝试将WebRTC引入其中。不出所料,我和贾纳斯一起去做…的工作。

测试WebRTC源代码的一种相对简单的方法,而不是发送SNL片段的脚本,可能是通常的RTP转发器:正如我在多个场合(包括几天前我的CommCon演示)所说的那样,我们经常使用它们,在这里也不会显得格格不入。只需创建一个VideoRoom发布器,RTP-将它们转发到rtp2ndi工具,工作就完成了。不过,出于几个原因,我稍后会讲到,我想要一个更集成的东西,一个可以单独使用的东西。

这导致我编写了一个新的Janus插件,它将允许WebRTC用户:

简而言之,我希望结合GStreamer管道提供的注入部分,利用Janus内核中集成的RTP服务器功能来接收数据包,并将rtp2ndi中的RTP到NDI过程嵌入到这个新插件中。这是一个非常简单的过程,所以我想出了一个简单的演示页面,允许Web用户插入NDI发送者的名称,然后像其他几个插件一样,使用Janus设置一个仅发送PeerConnection:

协商新的PeerConnection指示插件创建相关资源,即OPUS解码器、VP8解码器和具有所提供名称的NDI发送器。建立PeerConnection后,演示如下所示:

如您所见,没有什么突破性的东西:我们只是显示浏览器捕获并发送给Janus的本地流。然后,Janus内核像往常一样将未加密的音频和视频数据包传递给插件:Janus NDI插件被配置为解码它们并通过NDI中继未压缩的帧(与rtp2ndi之前所做的完全一样),这意味着通过WebRTC发起的流现在也可供NDI接收者使用,我们可以通过GStreamer NDI插件再次确认这一点:

这已经相当令人兴奋了,但仍然不是我真正想要实现的目标。事实上,如果您仔细想想,这确实允许Janus充当WebRTC/NDI网关,但是当处理您感兴趣的对话的Janus服务器实际上在Internet上,而不是您的LAN上(几乎总是这样)时,这并没有多大帮助。如果Janus位于Internet的某个位置(例如AWS上),则您无法对在那里创建的NDI流做太多操作:实际上,您根本无能为力,因为只有当所有流都在您的LAN网络环境中进行交换时,NDI才真正有意义。

因此,我决定将这一点再向前推进一步。更具体地说,我决定尝试让两个Janus实例相互对话:

目的很简单:在我的局域网中使用Janus通过WebRTC消费公共互联网上由Janus实际服务的流,以便本地Janus实例可以将远程提要转换为我确实可以在本地访问的NDI流。长话短说,将我的本地Janus实例用作从远程Janus实例接收媒体并将其网关到NDI的WebRTC“客户端”,如下图所示:

虽然这听起来很复杂,而且确实有点非常规,但Janus实例之间以这种方式交谈实际上并不少见。例如,有人使用这个技巧通过WebRTC将来自一个插件的媒体注入到另一个插件。要实现这一点,通常只需在两端协调Janus API调用,以便将其中一个(可能还有候选人)的SDP报价传递给另一个,并相应地发回SDP答案,从而使两个Janus实例彼此协商PeerConnection。这就是使用WebRTC这样的标准的好处!

我决定尝试这样做:特别是,我决定订阅Janus在线演示(Meetecho Spot)上的默认流媒体挂载点,并使用相关报价作为触发器,与我的Janus NDI插件协商新的PeerConnection。事实上,流插件订阅在功能上等同于Janus中的VideoRoom(SFU)订阅,这意味着它们是验证部署的一种简单而有效的方式。

尤里卡!。本地Janus实例作为订阅者通过WebRTC成功拉取了来自在线演示的远程流挂载点的视频,并作为GStreamer NDI接收者再次确认将其正确转换为NDI。

我希望你喜欢这篇简短的介绍,在我看来,这是一个有趣的新机会。当然,这主要是为了分享这个方向的一些初步工作:还有一些工作要做,特别是考虑到这还没有真正在实际生产环境中进行测试,或者没有使用除GStreamer NDI插件之外的任何其他NDI工具进行测试,因此我所做的一些假设可能需要进行一些调整。如果这在将来变得更有用,我还会考虑共享代码本身。

更重要的是,虽然我做概念验证的方式已经奏效了,但有人可能会争辩说,这不是做事情的最佳方式。事实上,正如我们在前一节中看到的,假设处理您感兴趣的对话/流的Janus实例和处理NDI转换的Janus实例实际上是不同的(通常是这样),这意味着在编排程序的帮助下让两个Janus实例彼此建立一个或多个PeerConnections。这是可行的,但是在生产LAN中仅为NDI转换过程需要一个Janus实例可能会被认为是一种矫枉过正的做法。

一个潜在的更好的替代方案可能是创建一个新的临时客户端应用程序,该应用程序能够执行几乎相同的事情,即:

通常,大部分复杂性在于WebRTC堆栈,这就是为什么在我的概念证明中我坚持使用Janus,因为它几乎是免费的。这就是说,在开放源码世界中有许多选项可以用于该目的:此外,我们自己的JAttack测试应用程序基本上就是这样,因此可以稍加改进以支持额外的NDI转换过程。

无论采用什么方法,这都将允许感兴趣的人只需生成一个客户端应用程序,并将其指向需要媒体的服务器,并且基本上可以让他们更好地控制整个过程。例如,应用程序可以配置为只连接到一个房间,并自动订阅所有贡献;或者可以指示它挑选来自不同来源的流;简而言之,我们之前概述的通用外部编排机制提供的任何内容都可以,但以一种更集成的方式提供。专用应用程序也将打开在客户端进行其他定制的大门:例如,此应用程序可能具有自己的UI并在您的桌面上运行,而不是在服务器上运行CLI应用程序。

假设对这项工作有足够的兴趣,这正是我下一步计划关注的。也许不是UI部分(我真的不擅长这些!),但是有一个专门的客户端确实会很酷!