我希望不断捕获屏幕区域。
我可以使用LockBits
,BitBlt
等来执行此操作,但是我的所有测量均显示,捕获单个帧平均需要30毫秒。似乎与VSynch非常相似...它将尝试将屏幕更新速率保持恒定为30ms ...
但是,我刚遇到following post。
其中有人声称可以在95毫秒内获得 1000帧 ...(对我来说是闻所未闻的)。这是他发布的代码:
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.Diagnostics;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private readonly Stopwatch sw = new Stopwatch();
private static Bitmap CaptureImage(int x, int y)
{
Bitmap b = new Bitmap(100, 100);
using (Graphics g = Graphics.FromImage(b))
{
g.CopyFromScreen(x, y, 0, 0, new Size(100, 100), CopyPixelOperation.SourceCopy);
g.DrawLine(Pens.Black, new Point(0, 27), new Point(99, 27));
g.DrawLine(Pens.Black, new Point(0, 73), new Point(99, 73));
g.DrawLine(Pens.Black, new Point(52, 0), new Point(52, 99));
g.DrawLine(Pens.Black, new Point(14, 0), new Point(14, 99));
g.DrawLine(Pens.Black, new Point(85, 0), new Point(85, 99));
}
return b;
}
private void button1_Click(object sender, EventArgs e)
{
Bitmap bmp = null;
sw.Restart();
for (int i = 0; i < 1000; i++)
{
bmp = CaptureImage(390, 420);
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
}
}
}
我已经尝试过了,猜猜怎么着...。我打印到控制台的时间大约是3万毫秒。因此很明显,在我的系统上,这些完全相同的代码仍然只能以30ms /帧的速度捕获。他在帖子中说:
如果系统相同,则肯定存在严重错误 程序需要35毫秒才能捕获1帧。
这让我感到奇怪,因此我更新了显卡驱动程序。结果相同。然后我以为我的显卡可能已经旧了……好吧,是:AMD Radeon HD 5700系列。由于怀疑VSync,因此我安装了AMD Catalyst Software Suite
,禁用了Vsyc并重新启动。再次运行测试,我得到了相同的结果:每1000帧大约3万毫秒。
然后,我在Amazon EC2 g2.2xlarge instance
上安装了Windows 10和NVIDIA GRID K520驱动程序(最新)。结果相同:每帧30ms。
有更多经验的人可以向我解释一下这里发生了什么吗?
难道就无法做到作者声称的那样并在95ms内捕获1000帧吗?
我的系统出问题了吗?我不知道还能尝试什么。
答案 0 :(得分:0)
使用当前技术基本上不可能达到100,000 fps。指向social.msdn.microsoft.com的链接包含有关实现此类结果的声明,但它们在从内存复制到内存与从屏幕复制到内存之间是错误的,或者可能是混淆的。
下面的示例使用核心WinAPI函数。在我的计算机上(使用便宜的板载图形卡),对于100 x 100像素的小区域,它每秒只能实现60帧。这将比所讨论的代码快一点,但是如果清理代码,则可能可以通过.net达到相同的结果。
无论如何,它只会导致计算机增加60 FPS或100 FPS(如果您尝试复制整个屏幕则更少)
请注意,从内存复制到内存的速度要快得多。我确实获得了超过100,000 FPS,但这不是屏幕上的实际帧。它只是从内存复制到内存。如果将区域增加到大于100x100像素,则速度会降低。
使用云计算机进行测试不可靠。我什至不知道将屏幕复制到云计算机上意味着什么。尝试在具有更好图形卡的台式机上进行测试。
class Program
{
[DllImport("user32.dll")]
static extern IntPtr GetDC(IntPtr ptr);
[DllImport("user32.dll")]
static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport("Gdi32.dll")]
static extern IntPtr CreateCompatibleDC(IntPtr hDC);
[DllImport("Gdi32.dll")]
static extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int w, int h);
[DllImport("Gdi32.dll")]
static extern IntPtr BitBlt(IntPtr hDC, int x, int y, int w, int h, IntPtr hSrc, int sx, int sy, int mode);
[DllImport("Gdi32.dll")]
static extern IntPtr SelectObject(IntPtr hdc, IntPtr obj);
[DllImport("Gdi32.dll")]
static extern int DeleteObject(IntPtr hdc);
[DllImport("Gdi32.dll")]
static extern int DeleteDC(IntPtr hdc);
static void Main(string[] args)
{
const int SRCCOPY = 0x00CC0020;
int w = 100;
int h = 100;
//get screen dc:
IntPtr hdc = GetDC((IntPtr)0);
//create memory dc and bitmap, select bitmap in to memory:
IntPtr memdc = CreateCompatibleDC(hdc);
IntPtr hbitmap = CreateCompatibleBitmap(hdc, w, h);
IntPtr holdbmp = SelectObject(memdc, hbitmap);
//create another memory dc and bitmap:
IntPtr memdc2 = CreateCompatibleDC(hdc);
IntPtr hbitmap2 = CreateCompatibleBitmap(hdc, w, h);
IntPtr holdbmp2 = SelectObject(memdc2, hbitmap2);
Stopwatch sw = new Stopwatch();
//copy the screen for 1 second
sw.Restart();
int fps = 0; //frames per second
for (fps = 0; sw.ElapsedMilliseconds < 1000; fps++)
BitBlt(memdc, 0, 0, w, h, hdc, 0, 0, SRCCOPY);
sw.Stop();
Console.WriteLine($"screen capture, FPS: {fps}");
//copy from memory to memory for 1 second
sw.Restart();
fps = 0;
for (fps = 0; sw.ElapsedMilliseconds < 1000; fps++)
BitBlt(memdc, 0, 0, w, h, memdc2, 0, 0, SRCCOPY);
sw.Stop();
Console.WriteLine($"memory to memory copy, FPS: {fps}");
//cleanup:
SelectObject(memdc, holdbmp);
SelectObject(memdc2, holdbmp2);
DeleteObject(hbitmap);
DeleteObject(hbitmap2);
DeleteDC(memdc);
DeleteDC(memdc2);
ReleaseDC((IntPtr)0, hdc);
}
}