对于初学者来说,我知道已经有了关于这方面的线索,但我似乎找不到符合我需求的答案,经过大约4个月的研究,我决定在这里问一个问题。
对于一个项目,我需要使屏幕截图循环。这些屏幕截图是基于是否使用显示器或屏幕截图的拍摄区域的用户参数进行的。(这意味着屏幕截图可能只是从显示器的一半左右制作的。)
问题是,它很慢。。。是的,我知道,如果我想做得更快,我必须使用这个库或那个directx等等。但是:我不知道directx,也找不到能够返回位图数据条带的开源lirary(realy更快)。此外,我还尝试了一些使用directx制作屏幕截图的教程,但无法正常运行。
关于性能,当只使用一个显示器时,性能实际上并没有那么差。(对于1440p分辨率,截屏时间约为40ms)
真正糟糕的是DWM。(我猜是dwm)。在制作屏幕截图时,除了在窗口中拖动外,其他一切都正常。比如,在youtube上看视频就可以了。但当我开始在窗户周围移动时,速度慢得要命。我截屏的时候,拖动的动画好像被屏蔽了。
现在来回答我的问题:
- 有人知道这种行为和/或有解决方案吗
- 我的替代品是什么(严肃的替代品。我的意思是30毫秒内3倍1440p的替代品)
编辑:这是我用来制作屏幕截图的方法
public void makeScreenshot(int i)
{
if (DisplayList[i].UseDisplay)
{
// copy from screen into graphics
this.graphicsList[i].CopyFromScreen(Screen.AllScreens[DisplayList[i].DisplayNo].Bounds.X, AreaTop[i], 0, 0, sizeList[i], CopyPixelOperation.SourceCopy);
// bitmapData is filled with LockBits from Screenshotted Bmp
bitmapData[i] = this.bitmapList[i].LockBits(rect[i], ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
// Pointer set to first pixel of Bitmap data
Iptr[i] = bitmapData[i].Scan0;
// Now Marshalcopy bitmapData to Pixel Array
Marshal.Copy(Iptr[i], Pixels[i], 0, Pixels[i].Length);
// Finaly unlock bits of Bitmap for next run
this.bitmapList[i].UnlockBits(bitmapData[i]);
}
}
有一个非常简单稳定的解决方案,我曾用于屏幕捕捉和直播,但它确实使用了一个外部库。也许你可以花几分钟来看看这个。我获得了6-15ms的1600x900屏幕截图。所以,你需要
- 幻影司机,你可以在这里:http://www.demoforge.com/dfmirage.htm
- 此示例应用程序:http://www.demoforge.com/sdk/MirrSharp.zip
我已经修改了示例解决方案的代码,以便每次启动桌面更改事件时都在PictureBox控件中显示屏幕。类似这样的东西:
private void _mirror_DesktopChange(object sender, DesktopMirror.DesktopChangeEventArgs e)
{
Trace.WriteLine(string.Format("Changed rect is {0},{1} ; {2}, {3} ({4})", new object[] { e.x1, e.y1, e.x2, e.y2, e.type }));
var perf = new Stopwatch();
perf.Start();
var bitmap = _mirror.GetScreen();
perf.Stop();
label1.Invoke(new Action<Int64>(i =>
{
pictureBox1.Image = bitmap;
label1.Text = i.ToString();
}), perf.ElapsedMilliseconds);
}
如果您关心性能,就不应该使用GDI来读取桌面。
DWM:性能注意事项和最佳实践
避免读取或写入显示器DC。虽然DWM支持它,但由于性能下降,我们不建议使用它。
尽管你没有这么做,但一些DirectDraw应用程序试图锁定整个桌面窗口进行绘制。在Windows7应用程序中,尝试该操作将失败-除了速度慢之外:
DirectDraw锁定
- Windows 7:Windows 7的应用程序无法调用DDRAW中的Lock API来锁定主桌面视频缓冲区。这样做将导致错误,并且将返回主的NULL指针。即使没有打开Desktop Window Manager Composition,也会强制执行此行为。与Windows 7兼容的应用程序不得锁定要渲染的主视频缓冲区
- Windows Vista(默认):应用程序将能够获取主视频缓冲区的锁定,因为传统应用程序依赖于此行为。运行应用程序会关闭桌面窗口管理器