正如您可能从问题标题中推测的那样,我们需要同时解码和显示多个(例如,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#应用程序中的那些。
有什么想法/建议?我完全在这里吃午饭吗?
如果存在一个完全不同的方法,我就更愿意采取一种完全不同的方法(这个项目需要大量的学习 - 赢得彩票的可能性比我在路上的每一步选择最佳方法的可能性更大)。
答案 0 :(得分:3)
忘记BitBlt-ing并执行此操作:
此外,我猜你可以将原始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关键字,其余的代码应该基本不变。