假设我有一个全屏运行的OpenGL游戏(Left 4 Dead 2)。我想以编程方式获取它的屏幕抓取然后将其写入视频文件。
我尝试过GDI,D3D和OpenGL方法(例如glReadPixels),并且在捕获流中接收空白屏幕或闪烁。
有什么想法吗?
对于它的价值,一个类似于我想要实现的东西的典型例子是Fraps。
答案 0 :(得分:14)
有一些方法可以解决这个问题。它们中的大多数都很蹩脚,它完全取决于您要定位的图形API类型以及目标应用程序使用的功能。 大多数DirectX,GDI +和OpenGL应用程序都是双重或三重缓冲的,因此它们都会调用:
void SwapBuffers(HDC hdc)
在某个时候。每当绘制窗口时,它们还在其消息队列中生成WM_PAINT消息。这为您提供了两个选择。
您可以在目标进程中安装全局钩子或线程本地钩子并捕获WM_PAINT消息。这允许您在绘画发生之前从设备上下文中复制内容。可以通过枚举系统上的所有进程并查找已知的窗口名称或已知的模块句柄来找到该过程。
您可以将代码注入目标进程的SwapBuffers本地副本。在Linux上,通过LD_PRELOAD环境变量或通过显式调用ld-linux.so.2可以很容易地做到这一点,但在Windows上没有等效性。幸运的是,Microsoft Research提供了一个框架,可以为您执行此操作,称为 Detours 。您可以在此处找到:link。
demoscene组Farbrausch制作了一个名为kkapture的演示捕获工具,该工具使用了Detours库。他们的工具针对的是不需要用户输入的应用程序,因此他们基本上通过挂钩所有可能的时间函数来运行演示,如timeGetTime(),GetTickCount()和QueryPerformanceCounter()。这完全是拉。 ryg(我认为?)关于kkapture的内部结构的演示可以找到here。我认为你感兴趣。
有关Windows挂钩的详细信息,请参阅here和here。
这个想法引起了我的兴趣,所以我使用Detours来加入OpenGL应用程序并弄乱图形。这是添加了绿雾的Quake 2:
Detours适用于两个级别。实际挂钩仅在与目标进程相同的进程空间中工作。所以Detours有一个函数,用于将DLL注入进程并强制其DLLMain运行,以及应该在该DLL中使用的函数。当运行DLLMain时,DLL应调用DetourAttach()来指定要挂钩的函数,以及“绕行”函数,这是您要覆盖的代码。
所以它基本上是这样的:
但有一些警告。运行DllMain时,稍后使用LoadLibrary()导入的库尚不可见。因此,您无法在DLL附件事件期间设置所有内容。解决方法是跟踪到目前为止被覆盖的所有函数,并尝试初始化您已经可以调用的这些函数中的其他函数。这样,只要LoadLibrary将它们映射到进程的内存空间,您就会发现新函数。我不太确定这对wglGetProcAddress有多好。 (也许这里的其他人有关于此的想法?)
某些LoadLibrary()调用似乎失败了。我使用Quake 2进行了测试,而DirectSound和waveOut API由于某种原因未能初始化。我还在调查这个。
答案 1 :(得分:0)
我找到了一个名为taksi的sourceforge项目:
但是,Taksi不提供音频捕捉。答案 2 :(得分:0)
我过去曾经写过屏幕抓取工具(DirectX7-9时代)。我发现好的旧 DirectDraw 工作得非常好,并且能够可靠地抓取硬件加速/视频屏幕内容,其他方法(D3D,GDI,OpenGL)似乎留空或加扰。它也很快。