如何最有效地向服务器发送连续的帧流

Posted

技术标签:

【中文标题】如何最有效地向服务器发送连续的帧流【英文标题】:How to send continuous stream of frames to server most efficiently 【发布时间】:2019-09-16 14:41:05 【问题描述】:

我正在尝试将帧从本地摄像头(树莓派摄像头,但也可能是我笔记本电脑的网络摄像头)发送到 Google 云实例,我在该实例上运行帧的 AI 处理。

我正在设法通过 http(即 tcp??)发送通过 opencv 捕获的帧,并在烧瓶服务器上接收它们。当烧瓶服务器在本地运行时,我可以获得良好的 fps(图像大小为 640x480 时 50+ fps),但是一旦我将帧发送到谷歌实例上的烧瓶应用程序,fps 急剧下降到 ~5fps。

我目前如何发送帧:

while True:
        frame = vs.read() #Separate thread, using cv2 to get the frame

        ret, jpeg = cv2.imencode('.jpg', frame)
        imgdata = jpeg.tobytes()
        response = requests.post(
            url='http://<IP address of google instance>:<port>',
            data= imgdata,
            headers='content-type':'image/jpeg',
            )

我发现这有两个问题: 1 - 使用 tcp 意味着我比 udp 协议慢,但是 udp 的字节大小有限。如果我错了,请纠正我,但是发送截断的帧并将它们重新放在服务器上似乎非常复杂.. 2 - 即使我有 udp 工作,也没有帧压缩,所以我永远无法达到有效的传输

我希望答案类似于使用 ffmpeg,但到目前为止我只知道如何使用 ffmpeg 在本地端口上流式传输帧,我不知道是否可以将帧发送到远程服务器。

关于最佳前进方向的任何建议?

【问题讨论】:

【参考方案1】:

根据您的情况正确选择的协议是 TCP。 UDP 不保证数据会以正确的顺序到达并且完好无损。在您的情况下,UDP 不会比 TCP 快(如果您确保数据完整且在您的代码中有序)。

您已经通过将图像转换为 jpg 来压缩图像。额外的压缩将非常低效。 TCP 和 UDP 均不压缩传输中的数据。

我相信现在您受到requests 库和将数据编码为 HTTP 协议的限制。您应该考虑使用纯 TCP,而没有 HTTP 的开销。这可以通过标准 python 库中的socket 模块来完成。但是,您的性能可能仍然很低,因为您没有帧间压缩并且仅使用帧内压缩。您需要考虑使用 ffmpeg 压缩相机中的数据,并使用您的程序或使用ffmpeg's point 2 point streaming 通过 TCP 发送流。

【讨论】:

非常感谢您的回答,非常有帮助。我很惊讶 TCP 并没有变慢,但对我来说很好,因为它看起来更容易:) Ffmpeg 仍然是我开始研究的一个黑盒子,但如果我无论如何都需要开始使用它,它是否可能更简单然后更有效地从命令行使用 ffmpeg 将帧流式传输到我的服务器(如果可行的话)?还是需要结合'socket'和'os.sendfile'一起发送到服务器? 网络性能是一个复杂的课题。严格来说,您可以像网卡一样快地通过 UDP 发送数据。当您的大量数据在网络上造成拥塞并且您的消息被提供商忽略时,问题就出现了。 TCP 建立连接的速度较慢,并且会限制传输速度,但它的运行速度接近目前网络可能的最大速度。它还负责完整性控制、重新传输丢失的数据等。简而言之,UDP 提供更低的延迟,但更高的错误率(丢失/损坏的数据)。 TCP 提供更高的延迟和可靠性。 对于 ffmpeg,快速粗略的谷歌搜索带来了这个:trac.ffmpeg.org/wiki/StreamingGuide#Pointtopointstreaming ffmpeg 允许通过 udp 或 tcp 发送和接收流。

以上是关于如何最有效地向服务器发送连续的帧流的主要内容,如果未能解决你的问题,请参考以下文章

如何正确地向客户端发送 HTTP 消息

通过网络连续传输图像的最有效方式

Window.onUnload 不一致地向服务器发送结果

最推荐的在Android中连续向服务器发送定期位置信息的方法?

如何让我的 Discord Bot 用 Ja​​vascript 编写以更快地发送消息?

在 Meteor 中如何有条件地向客户端发送数据?