【问题标题】:TCP or UDP? Delays building up on production for video streamTCP还是UDP?视频流的制作延迟
【发布时间】:2020-01-23 18:38:41
【问题描述】:

我正在使用 FFMPEG 和 nodejs 流 Duplex 类从相机创建视频流。

this.ffmpegProcess = spawn('"ffmpeg"', [

  '-i', '-',
  '-loglevel', 'info',

  /**
   * MJPEG Stream
   */

  '-map', '0:v',
  '-c:v', 'mjpeg',
  '-thread_type', 'frame', // suggested for performance on StackOverflow.
  '-q:v', '20', // force quality of image. 2-31 when 2=best, 31=worst
  '-r', '25', // force framerate
  '-f', 'mjpeg',
  `-`,

], {
  shell: true,
  detached: false,
});

在本地网络上,我们正在用几台计算机对其进行测试,每件事都非常稳定,延迟最长为 2 秒。

但是,我们已将该服务导入 AWS 生产环境,当我们连接第一台计算机时,我们有大约 2 秒的延迟,但如果另一个客户端连接到流,它们都会开始大量延迟,从而增加延迟到 10 多秒,此外视频非常慢,就像帧之间的运动一样。

现在我问 TCP 还是 UDP 是因为我们使用 TCP 作为流,这意味着发送的每个数据包都实现了 TCP syn-ack-synack 协议和序列。

我的问题是,TCP 真的会导致延迟达到 10 秒且动作非常慢的问题吗?因为在本地网络上它工作得非常好。

【问题讨论】:

  • 你的意思是每个数据包都有一个 TCP 连接?

标签: node.js ffmpeg stream


【解决方案1】:

是的,TCP 绝对不是正确的协议。可以使用,但在源端进行了一些修改。遗憾的是,UDP 不是灵丹妙药,如果没有额外的逻辑,UDP 也无法解决问题(如果您不关心会看到从其他帧随机构建的损坏帧)。

说明

TCP 的主要特点是数据包以正确的顺序传递,并且所有数据包都被传递。这两个功能非常有用,但对视频流非常有害。

本地网络带宽很大,丢包率也很低,所以 TCP 工作正常。在互联网上,带宽是有限的,每次达到限制都会导致数据包丢失。 TCP 将通过重新发送数据包来处理数据包丢失。每次重发都会导致流的延长延迟。

为了更好地理解,试着想象一个数据包包含整个帧(JPEG 图像)。假设链路的正常延迟为 100 毫秒(帧传输的时间)。对于 25 FPS,您需要每 40 毫秒传送一帧。如果帧在传输过程中丢失,TCP 将确保重新发送副本。 TCP 可以检测到这种情况并在 2 倍延迟 - 2 * 100 毫秒内修复理想情况(实际上它会更多,但为了简单起见,我保留了这个)。因此,在图像丢失期间,接收器队列中等待 5 帧并等待单个丢失帧。在此示例中,丢失一帧会导致 5 帧延迟。并且因为 TCP 创建了数据包队列。延迟永远不会减少,只会增长。在带宽足够的理想情况下,延迟仍然是一样的。

如何解决

我在 nodejs 中所做的是修复源端。 TCP中的数据包只有在源会做的情况下才能被跳过,TCP自己没有办法。

为此,我使用了事件drain。 该算法背后的想法是ffmpeg以自己的速度生成帧。 node.js 读取帧并始终保留最后收到的帧。它还具有单帧大小的传出缓冲区。因此,如果由于网络条件导致单帧的发送延迟,则来自 ffmpeg 的传入图像将被静默丢弃(这补偿了低带宽),除了最后接收的图像。因此,当 TCP 缓冲区(通过drain 事件)发出正确发送某些帧的信号时,nodejs 将获取最后接收到的图像并将其写入流中。

这个算法会自我调节。如果发送带宽足够(发送速度比 ffmpeg 生成的帧快),则不会丢弃任何数据包,并且将传送 25fps。如果带宽平均只能传输一半的帧,则将丢弃两帧中的一帧,因此接收器将保持 12.5fps 但不会增加延迟。

这个算法中最复杂的部分可能是正确地将字节流分割成帧。

【讨论】:

  • 感谢您的回答,在我发布此问题后,我们已经完全按照您所说的进行了实施,它确实提高了一点性能,但它很糟糕。事情变得缓慢,然后再次与快动作同步,我不知道为什么。我认为 facebook/instagram live 是一个预缓冲游戏,所以这就是为什么它看起来工作得非常快,但实际上你无法知道它们的真正延迟。
  • @BenBeri 另一种可能是使用WebRTC (UDP) + h.264(假设浏览器用于显示流)-您将获得更好的压缩率和性能,但我没有第一手经验使用这项技术。
【解决方案2】:

这可能与您的用例无关,但这是基于 HTTP 的内容交付系统(如 HLS)非常有用的地方。

UDP 或 TCP,尝试通过 Internet 实时传输数据是很困难的。

HLS 将输出可通过 HTTP 下载的文件(这在提供大文件时实际上非常有效,并确保视频的完整性,因为它内置了纠错等功能),并按顺序重新组装在客户端由播放器。

它可以轻松适应不同质量的流(协议的一部分),让客户端决定它使用数据的速度。

顺便说一句,Netflix 之类的公司使用 Widevine DRM,这有点相似 - 基于 HTTP 的内容交付,尽管 Widevine 将采用不同质量的编码,将其填充到一个巨大的文件中,并使用 HTTP 范围请求在质量之间切换流。

【讨论】:

  • 你应该看看 HLS 到底是什么:en.wikipedia.org/wiki/HTTP_Live_Streaming HLS 不是实时视频的最佳解决方案,因为它需要对视频流进行预处理,这会引入延迟。 HLS 使用 TCP 作为其传输(HTTP 是基于 TCP 的协议)。 Widevine 与本次讨论无关:它是一个身份验证和访问管理系统,适用于各种传输。如果使用 TCP 导致性能问题,使用 HLS 无法解决。
【解决方案3】:

在服务器或客户端上,运行wireshark 跟踪,这将告诉您数据包的确切“延迟”,或者哪一方没有做正确的事情。听起来服务器没有达到您的期望。确保流是 UDP。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多