最快的方式解码和同时显示许多H264视频C#

时间:2011-05-13 23:56:27

标签: c# optimization video pinvoke h.264

正如您可能从问题标题中推测的那样,我们需要同时解码和显示多个(例如,8个)H.264编码视频(并保持它们所有时间同步,但这是另一个问题的另一个问题) 。视频通常为25 FPS,分辨率为640x480。

在我解决问题的关键之前,我将提供一些背景知识。

该功能需要融入相当大的C#3.5(WinForms)应用程序。视频将占用应用程序中的矩形 - 托管代码需要能够指定每个视频的绘制位置以及大小。

我们在C#中获取H264数据包并将其激活到本机H264解码器以获取YUV12图像数据。

早期的尝试包括将YUV12图像转换为RGB24,将BitBlt将它们转换为从C#传递到本机代码的HWND。功能上,所有BitBlt都必须在UI线程上发生,这导致它在显示多个视频时陷入困境(在2.6 GHZ核心2二重奏上)。

当前尝试在启动时旋转一个线程每个cpu-core并负载平衡跨这些线程的视频解码/显示。这种表现是令人兴奋的(我发现观看任务管理器比显示的视频更有趣)。在UI方面,它还有很多不足之处。

我们从非UI线程开始绘制在UI线程上创建的HWND(例如,停靠在WinForms控件中的面板)的毫秒,我们开始因为非​​线程安全性而获得各种各样的时髦行为WinForms。这导致我们用本机代码创建HWND并绘制到那些,用C#提供它们应该在屏幕坐标中绘制的矩形。

尔加! CanOfWorms.Open()。

问题:当C#应用程序获得焦点时,它会跳转到Z-Order的前面并隐藏视频窗口。 解决方案:将视频窗口始终放在顶部。

问题:当用户切换到另一个应用程序时,视频窗口仍然位于顶部。 解决方案:检测C#应用程序的激活和停用,并相应地显示/隐藏视频窗口。

问题:用户说,“我想在另一台显示Word文档的同时在一台显示器上播放我的视频!” 解决方案:告诉用户闭嘴并且Word无论如何都很糟糕。

问题:我被解雇了。

等。等

我想问题的关键在于我们在非UI线程上创建了HWND,并且我们想要“模拟”嵌入在C#应用程序中的那些。

有什么想法/建议?我完全在这里吃午饭吗?

如果存在一个完全不同的方法,我就更愿意采取一种完全不同的方法(这个项目需要大量的学习 - 赢得彩票的可能性比我在路上的每一步选择最佳方法的可能性更大)。

3 个答案:

答案 0 :(得分:3)

忘记BitBlt-ing并执行此操作:

  • 对于您希望播放视频的每个窗口,创建一个DirectShow图形并将图形的渲染器附加到该窗口
  • 在图表中的渲染器之前放入samplegrabber过滤器。它将允许您进行回调,您可以在其中填充缓冲区
  • 而不是blitting,解码为samplegrabber中提供的缓冲区。

此外,我猜你可以将原始YUV12放入缓冲区,因为VMRenderer能够直接显示它们。

使用DirectShowNet库。

编辑:

是的,顺便说一下,如果视频在同一个'画布'上,你可以使用与渲染器相同的技术并只创建一个大窗口,然后“手动”移动解码的视频矩形并将它们放入帧缓冲区缓冲区。

另一个编辑:

BitBlts总是被序列化,即它们不能并行运行。

答案 1 :(得分:2)

  

我们从非UI线程开始绘制在UI线程上创建的HWND(例如,停靠在WinForms控件中的面板)的毫秒,我们开始因为非​​线程安全性而获得各种各样的时髦行为WinForms。这导致我们用本机代码创建HWND并绘制到那些,用C#提供它们应该在屏幕坐标中绘制的矩形。

什么样的时髦行为? 如果你的意思是闪烁或绘制延迟,你是否试图锁定()面板或任何其他类进行线程/绘图同步? 再次:当您将数据发送到解码器,接收图像,转换它然后使用OnPaint处理程序绘制它时,确切的问题是什么。 (设置一个以25fps循环的不同线程,调用panel1.Invalidate()然后)

  

我想问题的关键在于我们在非UI线程上创建了HWND,并且我们想要“模拟”嵌入在C#应用程序中的那些。

不要那样做。尝试在c#应用程序中绘制接收的数据。 一般来说,我不会建议混合本机代码和c#。在本机代码中使用h264解码器是唯一的例外。

使用你的线程解码视频数据包(正如你已经做的那样),然后让一个线程循环并调用Invalidate(如上所述)。然后为要显示视频的每个面板都有一个OnPaint处理程序。在此处理程序中获取最新的视频图片并绘制它(e.Graphics)。

我希望这会有所帮助,但也需要有关此问题的更多信息......

答案 2 :(得分:0)

我喜欢之前发布的DirectShow答案,但我希望根据您提问中的摘录添加一个可能更容易实现的附加选项:

  

虽然功能正常,但所有BitBlt都必须在UI线程上发生,导致它在显示多个视频时陷入困境

我的想法是从该代码开始,并使用currently available的Visual Studio 2010的Async CTP并包含上线许可证。从那里开始修改现有代码应该是一个相对简单的响应:只需在几个地方添加await和async关键字,其余的代码应该基本不变。