假设我有一个全屏运行的 OpenGL 游戏(Left 4 Dead 2)。我想以编程方式获取它的屏幕截图,然后将其写入视频文件。
我已经尝试过 GDI、D3D 和 OpenGL 方法(例如 glReadPixels),要么接收到空白屏幕,要么在捕获流中闪烁。
有任何想法吗?
就其值(value)而言,与我想要实现的目标类似的典型示例是 Fraps。
最佳答案
有几种方法可以解决这个问题。它们中的大多数都是 icky,这完全取决于您想要定位哪种图形 API,以及目标应用程序使用哪些功能。
大多数 DirectX、GDI+ 和 OpenGL 应用程序都是双重或三重缓冲的,因此它们都调用:
void SwapBuffers(HDC hdc)
在某一点。每当应绘制窗口时,它们还会在其消息队列中生成 WM_PAINT 消息。这为您提供了两种选择。演示场景组 Farbrausch 制作了一个名为 kkapture 的演示捕获工具,它利用了 Detours 库。然而,他们的工具针对不需要用户输入的应用程序,因此他们基本上通过 Hook 所有可能的时间函数(如 timeGetTime()、GetTickCount() 和 QueryPerformanceCounter())以固定帧速率运行演示。这完全是拉德。 ryg(我认为?)关于 kkapture 内部的演示文稿可以在 here 找到。 .我认为你对此很感兴趣。
有关 Windows Hook 的更多信息,请参阅 here和 here .
编辑:
这个想法引起了我的兴趣,所以我使用 Detours 来连接 OpenGL 应用程序并弄乱图形。这是添加了绿色雾的 Quake 2:
关于 Detours 如何工作的更多信息,因为我现在已经亲身使用了它:
Detours 在两个层面上起作用。实际的 Hook 仅在与目标进程相同的进程空间中起作用。因此,Detours 具有将 DLL 注入(inject)进程并强制其 DLLMain 也运行的函数,以及应该在该 DLL 中使用的函数。当 DLLMain 运行时,DLL 应该调用 DetourAttach() 来指定要 Hook 的函数,以及“detour”函数,这是您要覆盖的代码。
所以它基本上是这样工作的:
不过有一些警告。运行 DllMain 时,稍后使用 LoadLibrary() 导入的库尚不可见。因此,您不一定能在 DLL 附件事件期间设置所有内容。一种解决方法是跟踪到目前为止被覆盖的所有函数,并尝试在这些函数中初始化您已经可以调用的其他函数。这样,一旦 LoadLibrary 将新函数映射到进程的内存空间,您就会发现它们。我不太确定这对 wglGetProcAddress 有多好。 (也许这里的其他人对此有想法?)
一些 LoadLibrary() 调用似乎失败了。我用 Quake 2 进行了测试,但 DirectSound 和 waveOut API 由于某种原因未能初始化。我还在调查这个。
关于OpenGL/D3D : How do I get a screen grab of a game running full screen in Windows?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3486729/