我需要一些方法来获取屏幕数据并将其传递到我的应用程序中的DX9表面/纹理,并以 25fps 以 1600 * 900 分辨率呈现它,30会更好。
我尝试过BitBliting,但即使在那之后,我的速度为20fps,在将数据加载到纹理并渲染后,我的速度为11fps,远远落后于我的需要。
GetFrontBufferData是不可能的。
Here 与使用Windows Media API 有关,但我不熟悉它。示例将数据保存到文件中,也许它可以设置为为您提供单独的帧,但我没有找到足够好的文档来自己尝试。
我的代码:
m_memDC.BitBlt(0, 0, m_Rect.Width(),m_Rect.Height(), //m_Rect is area to be captured
&m_dc, m_Rect.left, m_Rect.top, SRCCOPY);
//at 20-25fps after this if I comment out the rest
//DC,HBITMAP setup and memory alloc is done once at the begining
GetDIBits( m_hDc, (HBITMAP)m_hBmp.GetSafeHandle(),
0L, // Start scan line
(DWORD)m_Rect.Height(), // # of scan lines
m_lpData, // LPBYTE
(LPBITMAPINFO)m_bi, // address of bitmapinfo
(DWORD)DIB_RGB_COLORS); // Use RGB for color table
//at 17-20fps
IDirect3DSurface9 *tmp;
m_pImageBuffer[0]->GetSurfaceLevel(0,&tmp); //m_pImageBuffer is Texture of same
//size as bitmap to prevent stretching
hr= D3DXLoadSurfaceFromMemory(tmp,NULL,NULL,
(LPVOID)m_lpData,
D3DFMT_X8R8G8B8,
m_Rect.Width()*4,
NULL,
&r, //SetRect(&r,0,0,m_Rect.Width(),m_Rect.Height();
D3DX_DEFAULT,0);
//12-14fps
IDirect3DSurface9 *frameS;
hr=m_pFrameTexture->GetSurfaceLevel(0,&frameS); // Texture of that is rendered
pd3dDevice->StretchRect(tmp,NULL,frameS,NULL,D3DTEXF_NONE);
//11fps
我发现,对于512 * 512平方,它以30fps运行(即490 * 450,20-25),所以我尝试划分屏幕,但似乎效果不佳。
如果代码中缺少某些内容请写,不要拒绝投票。感谢
答案 0 :(得分:10)
从Windows 8开始,有一个新的desktop duplication API可用于捕获视频内存中的屏幕,包括鼠标光标更改以及屏幕的哪些部分实际更改或移动。这比任何GDI或D3D9方法都更加高效,并且非常适合将桌面编码为视频流,因为您永远不必将纹理从GPU内存中拉出来。通过枚举DXGI输出并在要捕获的屏幕上调用DuplicateOutput,可以使用新的API。然后,您可以进入一个循环,等待屏幕更新并依次获取每个帧。
要将帧编码为视频,我建议您查看Media Foundation。有关编码视频帧的最简单方法,请特别注意Sink Writer。基本上,您只需将每个视频帧的D3D纹理包装到IMFSample对象中。这些可以直接传递到接收器编写器。有关详细信息,请参阅MFCreateDXGISurfaceBuffer和MFCreateVideoSampleFromSurface函数。为了获得最佳性能,通常您需要使用具有良好硬件编码支持的H.264编解码器(在大多数计算机上)。
为了完全披露,我在微软拥有桌面复制API的团队工作,我个人使用这种技术编写了以60fps的速度将桌面(以及视频,游戏等)捕获到视频文件的应用程序,以及很多其他场景。这也用于在微软内部进行屏幕流式传输,远程协助等等。
答案 1 :(得分:1)
如果您不喜欢FrontBuffer,请尝试使用BackBuffer:
LPDIRECT3DSURFACE9 surface;
surface = GetBackBufferImageSurface(&fmt);
将其保存到文件使用
D3DXSaveSurfaceToFile(filename, D3DXIFF_JPG, surface, NULL, NULL);