C#哪种屏幕拍摄速度最快?

我正在实现一个function,它将重复进行屏幕截图并在两个不同镜头之间输出脏矩形,然后在窗口中重新绘制屏幕。

我目前可以在20~30FPS之间运行。 它已经可以接受了。 但后来我做了一个基准并测量了它的性能。 发现Graphics.CopyFromScreen()占用了最多50%的处理时间。 (是的。即使在最坏的情况下,它仍然需要比找到所有脏矩形更长的时间)然后我使用本机API实现BitBlt()并没有得到任何改进。

我知道在这种情况下可能没有任何实际的理由让它快于30FPS。 我只是想知道,有没有更快的方式拍摄屏幕截图?

谢谢。

这与几年前提出的问题非常相似: 这里 。 那个问题是directx的捕获能力是否可以用来获得更好的性能。

一致认为它可能不会提供任何性能提升,TightVNC通过作弊很快就能做到。 它使用的驱动程序不必使用(可能).NET正在使用的API。

在某些时候,我记得看看Camstudio的源代码,我相信他们使用directx的捕获function。 我认为你不能超过30 fps,而且大部分时间都没有。 我不确定这是一个问题,camstudio用来确定什么时候发生了变化或实际的捕获机制。

对于那些来到这个主题的人,我来到了这个解决方案:

 using SharpDX; using SharpDX.Direct3D11; using SharpDX.DXGI; using System; using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Threading.Tasks; 

您将需要SharpDX和SharpDX.Direct3D11软件包

 public class ScreenStateLogger { private byte[] _previousScreen; private bool _run, _init; public int Size { get; private set; } public ScreenStateLogger() { } public void Start() { _run = true; var factory = new Factory1(); //Get first adapter var adapter = factory.GetAdapter1(0); //Get device from adapter var device = new SharpDX.Direct3D11.Device(adapter); //Get front buffer of the adapter var output = adapter.GetOutput(0); var output1 = output.QueryInterface(); // Width/Height of desktop to capture int width = output.Description.DesktopBounds.Right; int height = output.Description.DesktopBounds.Bottom; // Create Staging texture CPU-accessible var textureDesc = new Texture2DDescription { CpuAccessFlags = CpuAccessFlags.Read, BindFlags = BindFlags.None, Format = Format.B8G8R8A8_UNorm, Width = width, Height = height, OptionFlags = ResourceOptionFlags.None, MipLevels = 1, ArraySize = 1, SampleDescription = { Count = 1, Quality = 0 }, Usage = ResourceUsage.Staging }; var screenTexture = new Texture2D(device, textureDesc); Task.Factory.StartNew(() => { // Duplicate the output using (var duplicatedOutput = output1.DuplicateOutput(device)) { while (_run) { try { SharpDX.DXGI.Resource screenResource; OutputDuplicateFrameInformation duplicateFrameInformation; // Try to get duplicated frame within given time is ms duplicatedOutput.AcquireNextFrame(5, out duplicateFrameInformation, out screenResource); // copy resource into memory that can be accessed by the CPU using (var screenTexture2D = screenResource.QueryInterface()) device.ImmediateContext.CopyResource(screenTexture2D, screenTexture); // Get the desktop capture texture var mapSource = device.ImmediateContext.MapSubresource(screenTexture, 0, MapMode.Read, SharpDX.Direct3D11.MapFlags.None); // Create Drawing.Bitmap using (var bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb)) { var boundsRect = new Rectangle(0, 0, width, height); // Copy pixels from screen capture Texture to GDI bitmap var mapDest = bitmap.LockBits(boundsRect, ImageLockMode.WriteOnly, bitmap.PixelFormat); var sourcePtr = mapSource.DataPointer; var destPtr = mapDest.Scan0; for (int y = 0; y < height; y++) { // Copy a single line Utilities.CopyMemory(destPtr, sourcePtr, width * 4); // Advance pointers sourcePtr = IntPtr.Add(sourcePtr, mapSource.RowPitch); destPtr = IntPtr.Add(destPtr, mapDest.Stride); } // Release source and dest locks bitmap.UnlockBits(mapDest); device.ImmediateContext.UnmapSubresource(screenTexture, 0); using (var ms = new MemoryStream()) { bitmap.Save(ms, ImageFormat.Bmp); ScreenRefreshed?.Invoke(this, ms.ToArray()); _init = true; } } screenResource.Dispose(); duplicatedOutput.ReleaseFrame(); } catch (SharpDXException e) { if (e.ResultCode.Code != SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code) { Trace.TraceError(e.Message); Trace.TraceError(e.StackTrace); } } } } }); while (!_init) ; } public void Stop() { _run = false; } public EventHandler ScreenRefreshed; } 

此代码将尽可能快地从图形设备的前缓冲区获取帧,并从它创建的位图中检索byte []。 代码似乎在内存和处理器使用方面(GPU和CPU)稳定。

用法:

 var screenStateLogger = new ScreenStateLogger(); screenStateLogger.ScreenRefreshed += (sender, data) => { //New frame in data }; screenStateLogger.Start(); 

要替代CopyFromScreen()请选中此项 。 请注意, Graphics.CopyFromScreen()本身调用API BitBlt()从屏幕复制,您可以使用Reflector检查源代码。