5

我需要一些方法来获取屏幕数据并将它们传递给我的应用程序中的 DX9 表面/纹理,并在1600*900分辨率下以至少25fps的速度渲染它,30 会更好。

我尝试了 BitBliting,但即使在那之后我还是 20fps,并且在将数据加载到纹理并渲染它之后,我还是 11fps,这远远落后于我的需要。

GetFrontBufferData 是没有问题的。

是有关使用 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 的速度运行(即 20-25 的 490*450),所以我尝试分割屏幕,但似乎效果不佳。

如果代码中缺少某些内容,请写下来,不要投反对票。谢谢

4

2 回答 2

12

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

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

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

于 2014-03-06T08:38:50.543 回答
1

如果你不喜欢 FrontBuffer,试试 BackBuffer:

LPDIRECT3DSURFACE9  surface;
surface = GetBackBufferImageSurface(&fmt);

将其保存到文件使用

D3DXSaveSurfaceToFile(filename, D3DXIFF_JPG, surface, NULL, NULL);
于 2013-01-28T11:42:14.920 回答