DirectX中的整个屏幕捕获和渲染[性能]

时间:2013-01-25 18:03:04

标签: c++ winapi directx ms-media-foundation

我需要一些方法来获取屏幕数据并将其传递到我的应用程序中的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),所以我尝试划分屏幕,但似乎效果不佳。

如果代码中缺少某些内容请写,不要拒绝投票。感谢

2 个答案:

答案 0 :(得分:10)

从Windows 8开始,有一个新的desktop duplication API可用于捕获视频内存中的屏幕,包括鼠标光标更改以及屏幕的哪些部分实际更改或移动。这比任何GDI或D3D9方法都更加高效,并且非常适合将桌面编码为视频流,因为您永远不必将纹理从GPU内存中拉出来。通过枚举DXGI输出并在要捕获的屏幕上调用DuplicateOutput,可以使用新的API。然后,您可以进入一个循环,等待屏幕更新并依次获取每个帧。

要将帧编码为视频,我建议您查看Media Foundation。有关编码视频帧的最简单方法,请特别注意Sink Writer。基本上,您只需将每个视频帧的D3D纹理包装到IMFSample对象中。这些可以直接传递到接收器编写器。有关详细信息,请参阅MFCreateDXGISurfaceBufferMFCreateVideoSampleFromSurface函数。为了获得最佳性能,通常您需要使用具有良好硬件编码支持的H.264编解码器(在大多数计算机上)。

为了完全披露,我在微软拥有桌面复制API的团队工作,我个人使用这种技术编写了以60fps的速度将桌面(以及视频,游戏等)捕获到视频文件的应用程序,以及很多其他场景。这也用于在微软内部进行屏幕流式传输,远程协助等等。

答案 1 :(得分:1)

如果您不喜欢FrontBuffer,请尝试使用BackBuffer:

LPDIRECT3DSURFACE9  surface;
surface = GetBackBufferImageSurface(&fmt);

将其保存到文件使用

D3DXSaveSurfaceToFile(filename, D3DXIFF_JPG, surface, NULL, NULL);