通过 Socket 传输视频帧

Posted

技术标签:

【中文标题】通过 Socket 传输视频帧【英文标题】:Transferring frames of a Video over Socket 【发布时间】:2013-02-18 17:27:24 【问题描述】:

我的 C# 代码中有 30FPS 的视频帧,我想在本地主机中广播它,以便所有其他应用程序都可以使用它。我虽然因为它是一个视频并且不担心任何数据包丢失并且不需要从客户端连接/接受,所以 UDP 是一个不错的选择。

但是这里有很多问题。

如果我用UDP单播速度就够了,大概25FPS(CPU使用率是25% 这意味着在我的 4 核 CPU 中的一个线程上 100%,这并不理想。但 至少它发送了足够的数据集)。但单播无法传递数据 致所有客户。 如果我使用广播速度非常低。在 CPU 使用率相同的情况下大约 10FPS。

我能做什么?!数据在同一台计算机上,因此无需从 LAN 等远程访问。我只想要一种在同一台机器的不同应用程序之间每秒传输约 30MBytes 数据的方法。 (640x480 是固定大小的 Image x 30fps x 3byte per pixel is about 27000KByte per second)

    UDP 组播性能更好吗?! 即使我接受每个客户端,TCP 是否可以给我更好的性能 并独立发送给他们?! 还有比Socket更好的方法吗?!内存共享什么的?! 为什么 UDP 广播这么慢?!每只大约 10MBytes 第二个?! 有没有一种快速的方法来压缩高性能的帧(到 每秒编码 30fps 并在其他部分解码)?客户端应用程序在 C++ 所以这一定是一种跨平台的方式。

我只是想在这里了解其他开发者的经验和想法,所以请写下你的想法。

编辑:

有关数据的更多信息:数据采用位图 RGB24 格式,它们以 30FPS 的速度从设备流式传输到我的应用程序。我想将此数据广播到其他应用程序,他们需要再次将这些图像设为 RGB24 格式。没有标题或任何东西,只有固定大小的位图数据。所有操作都必须即时执行。无论使用有损压缩算法还是其他任何东西。

【问题讨论】:

是否有一些现有的流媒体视频协议之一不适合的原因,以及为什么使用众多视频流解决方案之一不起作用?这是一个已通过多种不同方式解决的问题。当然,其中一种方法应该可以满足您的需求,并且不需要您重新发明***。 @Pete,你知道任何基于 UDP 的跨平台(.Net、C++)视频流库吗?!不幸的是我找不到一个。因为在没有库的情况下实现这些协议之一并不比发明整个解决方案更容易。 FFMPEG 不是一个用于转换(编码/解码)视频格式的命令行应用程序吗?!如何将它用于 .Net 中的位图对象流式传输?! 【参考方案1】:

我在工业环境中试验组播,在不成熟的可靠网络上是一个不错的选择

本地主机中,共享内存可能是一个不错的选择,因为您可以构建一个帧的循环队列并从一个翻转到next 仅使用单个互斥锁来保护指针分配(写入端)。一个作家,几个读者,没有问题。

在使用 C++ C#的 Windows 上,共享内存称为文件映射,但您可以使用系统分页文件(RAM 和/或磁盘)。

查看这些链接了解更多信息

http://msdn.microsoft.com/en-us/library/system.io.memorymappedfiles.aspx http://msdn.microsoft.com/en-us/library/dd997372.aspx 混合 C++ 和 C#:How to implement shared memory in .NET? Fully managed shared memory .NET implementations?

共享内存空间不受保护或私有,但已命名。

通常,作者进程创建它,读者通过它的名称打开它。防病毒软件会以与其他所有 I/O 相同的方式查看此类 I/O,但不会阻止通信。

以下是文件映射的示例:

char shmName[MAX_PATH+1];
sprintf( shmName, "shmVideo_%s", name );
shmName[MAX_PATH] = '\0';
_hMap =
   CreateFileMapping(
      INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, size, shmName );
if( _hMap == 0 ) 
   throw OSException( __FILE__, __LINE__ );

_owner = ( GetLastError() != ERROR_ALREADY_EXISTS );
_mutex = Mutex::getMutex( name );
Synchronize sync( *_mutex );
_data = (char *)MapViewOfFile( _hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
if( _data == 0 ) 
   throw OSException( __FILE__, __LINE__ );

【讨论】:

这似乎是一个很好的答案。谢谢,但是我有很多关于内存映射文件的问题。首先,如何从非托管端(C++ 客户端)访问其他托管进程内存文件?!其次,用户权限、杀毒软件和其他安全软件/限制呢?! 好的,谢谢。让我看看,我会接受你的回答。目前我不能给予赏金,因为它需要更多的 7 小时 :) 目前使用的是内存映射文件,性能非常好。幸运的是,从托管和非托管端访问它没有问题。只有一些人可能需要注意的是不需要精确度的多进程写入。谢谢。【参考方案2】:

将 live555 http://www.live555.com/ 与您最喜欢的压缩器 - ffmpeg 结合使用进行流式传输。

【讨论】:

那么我怎样才能用它来发送数据的位图呢?!这是一个 Live cam,所以我无法将它们保存到磁盘然后使用 FFMPEG 将它们转换为视频,然后使用 Live555 发送它们!我需要某种实时解决方案,它能够将 30 个位图从内存编码到视频(再次在内存中,位图正在流式传输,因此在应用程序启动时它们不可用),然后使用其他解决方案(或同一个库,或者我可以写这个发送部分)将它们发送到其他应用程序。他们还必须能够将数据解码为内存中的 RGB 数据帧。

以上是关于通过 Socket 传输视频帧的主要内容,如果未能解决你的问题,请参考以下文章

android实时传输视频Socket

Socket网络编程

udp socket: 简单的数据包与视频流传输

[8421论坛]2019 Socket网络编程入门到进阶与实战完整视频教程

通过 socket.io 流式传输实时音频

通过 websockets 的 Socket.io - 随机“传输端”断开连接