快速桌面图像捕获

时间:2014-11-25 15:12:00

标签: c# winforms screenshot

我正在尝试在C#中开发基本的屏幕共享和协作应用程序。我目前正在捕获屏幕,查找已更改的屏幕区域,随后需要将其传输到最终客户端。

我遇到的问题是屏幕捕获的整体帧速率太低。我有一个相当不错的算法来查找已更改的屏幕区域。给定屏幕上的字节像素阵列,它计算在2-4ms内改变的区域,但是我得到的总帧速率是15-18fps(即每帧约60ms)。瓶颈是将屏幕上的数据捕获为字节数组,大约需要35-50ms。我尝试了几种不同的技术,并且不能将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);

对于单个1080p屏幕,只需运行上面的代码大约需要45毫秒。这使得整体帧速率太慢而不能平滑,因此我尝试使用DirectX,如下例所示:

http://www.codeproject.com/Articles/274461/Very-fast-screen-capture-using-DirectX-in-Csharp

然而,这并没有真正取得任何成果。它略微提高了屏幕捕获的速度,但它仍然太慢(大约需要25-40ms,并且小的增加不值得额外的DLL,代码等的开销。

在谷歌搜索后我无法找到更好的解决方案,所以我的问题是捕获当前显示在屏幕上的像素的最佳方法是什么?理想的解决方案是:

  • 将屏幕捕获为RGBA
  • 的字节数组
  • 在较旧的Windows平台(例如Windows XP及更高版本)上工作
  • 使用多个显示器
  • 使用现有的系统库而不是第三方DLL

所有这些要点都可以通过一个可以返回合适的整体帧率的解决方案,在实际捕获的5-10ms范围内,因此帧率可以是40-60fps。

或者,如果没有与上述匹配的解决方案,我是否采用了错误的路径来计算屏幕更改。有没有更好的方法来计算已更改的屏幕区域?

1 个答案:

答案 0 :(得分:0)

也许您可以在较低级别的代码中访问屏幕缓冲区并直接挂钩到Windows用作其屏幕更新的一部分的区域和区域。听起来你是在原始显示更改之后,Windows已经必须跟踪这些数据。只是在找到更有知识的人时,为你提供指导。