快速的桌面图像捕获
本文关键字:图像 桌面 | 更新日期: 2023-09-27 18:32:07
我正在尝试用 C# 开发一个基本的屏幕共享和协作应用程序。我目前正在捕获屏幕,查找屏幕中已更改并随后需要传输到最终客户端的区域。
我遇到了一个问题,因为屏幕截图的整体帧速率太低。我有一个相当好的算法来查找屏幕中已更改的区域。给定屏幕上的像素字节数组,它会计算在 2-4 毫秒内变化的区域,但是我得到的整体帧速率为 15-18 fps(即每帧大约需要 60 毫秒)。瓶颈是将屏幕上的数据捕获为字节数组,大约需要 35-50 毫秒。我已经尝试了几种不同的技术,但无法将 fps 推到 20 以上。
起初我尝试了这样的事情:
var _bmp = new Bitmap(screenSectionToMonitor.Width, screenSectionToMonitor.Height);
var _gfx = Graphics.FromImage(_bmp);
_gfx.CopyFromScreen(_screenSectionToMonitor.X, _screenSectionToMonitor.Y, 0, 0, new Size(_screenSectionToMonitor.Width, _screenSectionToMonitor.Height), CopyPixelOperation.SourceCopy);
var data = _bmp.LockBits(new Rectangle(0, 0, _screenSectionToMonitor.Width, _screenSectionToMonitor.Height), ImageLockMode.ReadOnly, _bmp.PixelFormat);
var ptr = data.Scan0;
Marshal.Copy(ptr, _screenshot, 0, _screenSectionToMonitor.Height * _screenSectionToMonitor.Width * _bytesPerPixel);
_bmp.UnlockBits(data);
这太慢了,大约需要 45 毫秒才能为单个 1080p 屏幕运行上面的代码。这使得整体帧速率太慢而无法流畅,因此我随后尝试按照此处的示例使用 DirectX:
http://www.codeproject.com/Articles/274461/Very-fast-screen-capture-using-DirectX-in-Csharp
然而,这并没有真正取得任何结果。它略微提高了屏幕捕获的速度,但仍然太慢了(大约需要 25-40 毫秒,而且小幅增加不值得额外的 DLL、代码等开销。
在谷歌上搜索了一会儿之后,我真的找不到更好的解决方案,所以我的问题是捕获屏幕上当前显示的像素的最佳方法是什么?理想的解决方案是:
- 将屏幕捕获为RGBA格式的字节数组
- 在较旧的Windows平台上工作(例如Windows XP及更高版本)
- 使用多台显示器
- 使用现有系统库而不是第三方 DLL
所有这些要点对于返回体面的整体帧速率的解决方案都是可以协商的,实际捕获在 5-10 毫秒的范围内,因此帧速率可以是 40-60fps。
或者,如果没有与上述匹配的解决方案,我是否选择了错误的路径来计算屏幕更改。有没有更好的方法来计算屏幕中已更改的区域?
也许您可以在较低级别的代码中访问屏幕缓冲区,并直接挂钩到 Windows 用作其屏幕更新一部分的层和区域。听起来您是在原始显示更改之后,Windows已经必须跟踪此数据。只是为你提供一个方向,当你找到一个知识渊博的人时。