Windows上最快的屏幕捕获方法

我想为Windows平台编写一个截屏程序,但不确定如何捕获屏幕。 我所知道的唯一方法是使用GDI,但我很好奇是否还有其他方法可以解决这个问题,如果有的话,会产生最少的开销? 速度是一个优先事项。

屏幕录像程序将用于录制游戏镜头,但是,如果这确实缩小了选项范围,我仍然可以接受任何其他超出此范围的建议。 毕竟知识还不错。

编辑 :我遇到过这篇文章: 捕获屏幕的各种方法 。 它向我介绍了Windows Media API的实现方式以及DirectX的实现方式。 它在结论中提到禁用硬件加速可以大大提高捕获应用程序的性能。 我很好奇为什么会这样。 任何人都可以为我填补遗失的空白吗?

编辑 :我读过像Camtasia这样的截屏程序使用他们自己的捕获驱动程序。 有人能给我一个深入的解释它是如何工作的,为什么它更快? 我可能还需要有关实现类似内容的指导,但我确信无论如何都有现有的文档。

另外,我现在知道FRAPS如何记录屏幕。 它挂钩底层图形API以从后台缓冲区读取。 根据我的理解,这比从前端缓冲区读取更快,因为您正在从系统RAM而不是videoRAM中读取数据。 你可以在这里阅读这篇文章。

这是我用来收集单帧的内容,但是如果你修改它并保持两个目标一直打开,那么你可以使用文件名的静态计数器将它“流”到磁盘。 – 我不记得我发现了什么,但它已被修改,感谢谁!

 void dump_buffer() { IDirect3DSurface9* pRenderTarget=NULL; IDirect3DSurface9* pDestTarget=NULL; const char file[] = "Pickture.bmp"; // sanity checks. if (Device == NULL) return; // get the render target surface. HRESULT hr = Device->GetRenderTarget(0, &pRenderTarget); // get the current adapter display mode. //hr = pDirect3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&d3ddisplaymode); // create a destination surface. hr = Device->CreateOffscreenPlainSurface(DisplayMde.Width, DisplayMde.Height, DisplayMde.Format, D3DPOOL_SYSTEMMEM, &pDestTarget, NULL); //copy the render target to the destination surface. hr = Device->GetRenderTargetData(pRenderTarget, pDestTarget); //save its contents to a bitmap file. hr = D3DXSaveSurfaceToFile(file, D3DXIFF_BMP, pDestTarget, NULL, NULL); // clean up. pRenderTarget->Release(); pDestTarget->Release(); } 

编辑:我可以看到,这是在您的第一个编辑链接下列为“GDI方式”。 即使使用该网站上的性能咨询,这仍然是一个不错的方式,你可以轻松地达到30fps。

从这个评论(我没有经验这样做,我只是引用了一个人):

 HDC hdc = GetDC(NULL); // get the desktop device context HDC hDest = CreateCompatibleDC(hdc); // create a device context to use yourself // get the height and width of the screen int height = GetSystemMetrics(SM_CYVIRTUALSCREEN); int width = GetSystemMetrics(SM_CXVIRTUALSCREEN); // create a bitmap HBITMAP hbDesktop = CreateCompatibleBitmap( hdc, width, height); // use the previously created device context with the bitmap SelectObject(hDest, hbDesktop); // copy from the desktop device context to the bitmap device context // call this once per 'frame' BitBlt(hDest, 0,0, width, height, hdc, 0, 0, SRCCOPY); // after the recording is done, release the desktop context you got.. ReleaseDC(NULL, hdc); // ..and delete the context you created DeleteDC(hDest); 

我不是说这是最快的,但如果你在兼容的设备上下文之间进行复制, BitBlt操作通常会非常快。

作为参考, Open Broadcaster Software实现了类似这样的“dc_capture”方法,虽然不是使用CreateCompatibleDC创建目标上下文IDXGISurface1 ,但它们使用IDXGISurface1 ,它与DirectX 10+一起使用。 如果没有对此的支持,则返回CreateCompatibleDC

要将其更改为使用特定应用程序,您需要将第一行更改为GetDC(game) ,其中game是游戏窗口的句柄,然后设置游戏窗口的正确heightwidth

一旦你有hDest / hbDesktop中的像素,你仍然需要将它保存到一个文件,但如果你正在进行屏幕捕获,那么我认为你会想要在内存中缓冲一定数量的像素并保存到video文件中在块中,所以我不会指向将静态图像保存到磁盘的代码。

我写了一个video捕获软件,类似于FRAPS for DirectX应用程序。 源代码可用,我的文章解释了一般技术。 请查看http://sofzh.miximages.com/c%2B%2B/保存表面 D3DXSaveSurfaceToFileA(“filename.png”,D3DXIFF_PNG,surface,NULL,NULL);

SAFE_RELEASE(表面);

要做到这一点,你应该创建你的swapbuffer

 d3dpps.SwapEffect = D3DSWAPEFFECT_COPY ; // for screenshots. 

(所以你保证在你拍摄截图之前,后备缓冲区没有被破坏)。

我写了一个实现屏幕捕获的GDI方法的类。 我也想要额外的速度,所以,在发现DirectX方法(通过GetFrontBuffer)后,我试过了,期待它更快。

我很沮丧地发现GDI的速度提高了约2.5倍。 在100次试验捕获我的双显示器显示后,GDI实现平均每屏截屏0.65秒,而DirectX方法平均为1.72秒。 因此,根据我的测试,GDI肯定比GetFrontBuffer快。

我无法让Brandrew的代码通过GetRenderTargetData测试DirectX。 屏幕副本纯粹是黑色的。 但是,它可以超快地复制那个空白屏幕! 我会继续修补它,并希望得到一个工作版本,看看它的真实结果。

在我的印象中,GDI方法和DX方法的性质不同。 使用GDI绘制应用FLUSH方法,FLUSH方法绘制帧然后清除它并在同一缓冲区中重绘另一帧,这将导致游戏中需要高帧率的闪烁。

  1. 为什么DX更快? 在DX(或图形世界)中,应用了一种称为双缓冲区渲染的更成熟的方法,其中存在两个缓冲区,当前缓冲区存在于硬件时,您也可以渲染到另一个缓冲区,然后在帧1之后完成渲染后,系统交换到另一个缓冲区(锁定它以呈现给硬件,并释放前一个缓冲区),这样就大大提高了渲染效率。
  2. 为什么要更快地降低硬件加速? 虽然使用双缓冲区渲染,但FPS得到了改进,但渲染时间仍然有限。 现代图形硬件在渲染过程中通常需要进行大量优化,例如抗锯齿,这是非常耗费计算的,如果你不需要高质量的图形,当然你可以禁用这个选项。 这会节省你一些时间。

我认为你真正需要的是一个重播系统,我完全同意人们讨论的内容。

对于C ++,您可以使用: http : //www.pinvoke.net/default.aspx/gdi32/BitBlt.html
这可能不适用于所有类型的3D应用程序/video应用程序。 然后, 此链接可能更有用,因为它描述了您可以使用的3种不同方法。

旧答案(C#):
您可以使用System.Drawing.Graphics.Copy ,但速度不是很快。

我写的一个示例项目就是这样做的: http : //blog.tedd.no/index.php/2010/08/16/c-image-analysis-auto-gaming-with-source/

我打算使用像Direct3D这样的更快的方法来更新这个示例: http : //spazzarama.com/2009/02/07/screencapture-with-direct3d/

以下是捕获video的链接: 如何使用C#.Net将屏幕捕获为video?

我已经能够收集的一些东西:显然使用“镜像驱动程序”虽然我不知道OSS的速度很快。

与其他遥控软件相比,为什么RDP如此之快?

显然使用StretchRect的一些卷积比BitBlt更快

http://betterlogic.com/roger/2010/07/fast-screen-capture/comment-page-1/#comment-5193

你提到的那个(连接到D3D dll)可能是D3D应用程序的唯一方法,但不适用于Windows XP桌面捕获。 所以现在我只是希望普通的桌面窗口有一个相当于速度的fraps …任何人?

(我认为使用aero你可能会使用类似fraps的钩子,但XP用户会运气不好)。

显然也会改变屏幕位深度和/或禁用硬件加速。 可能会帮助(和/或禁用航空)。

https://github.com/rdp/screen-capture-recorder-program包含一个相当快的基于BitBlt的捕获实用程序,以及作为其安​​装的一部分的基准测试程序,它可以让您对BitBlt速度进行基准测试以优化它们。

VirtualDub还有一个“opengl”屏幕捕获模块,据称速度很快,可以执行更改检测等操作http://www.virtualdub.org/blog/pivot/entry.php?id=290

你可以试试c ++开源项目WinRobot @git ,一个强大的屏幕截图

 CComPtr pService; hr = pService.CoCreateInstance(__uuidof(ServiceHost) ); //get active console session CComPtr pUnk; hr = pService->GetActiveConsoleSession(&pUnk); CComQIPtr pSession = pUnk; // capture screen pUnk = 0; hr = pSession->CreateScreenCapture(0,0,1280,800,&pUnk); // get screen image data(with file mapping) CComQIPtr pBuffer = pUnk; 

支持:

  • UAC窗口
  • Winlogon中
  • DirectShowOverlay

我自己用directx来做,并认为它和你想要的一样快。 我没有快速的代码示例,但我发现这应该是有用的。 directx11版本不应该有很大差异,directx9可能会多一点,但这就是要走的路

我意识到以下建议没有回答你的问题,但我发现捕获快速变化的DirectX视图的最简单方法是将摄像机插入video卡的S-video端口,并将图像记录为电影。 然后将video从相机传输回计算机上的MPG,WMV,AVI等文件。