递归火山软件开发平台

标题: 尝试了很多次,无法封装D3D 截图,希望分享一下,谢谢! [打印本页]

作者: urenai    时间: 3 天前
标题: 尝试了很多次,无法封装D3D 截图,希望分享一下,谢谢!
大致分为2部分,
1、获取数据。
2、数据还原成bmp图片

不管怎么优化,普通截图速度都不可能降到50毫秒以下。

作者: fengshangren    时间: 3 天前
D3D截图我一直不太清楚是什么,有什么优势,和DXGI有什么区别,哪个快
作者: urenai    时间: 3 天前
fengshangren 发表于 2025-1-15 22:30
D3D截图我一直不太清楚是什么,有什么优势,和DXGI有什么区别,哪个快

兄弟分享一下 DXGI
作者: uuyyhhjj    时间: 前天 20:46
Desktop Duplication API 我用AI试了下,始终是黑屏,没接触过D3D,表面上看不出来哪个环节出问题了

  1. #include <windows.h>
  2. #include <d3d11.h>
  3. #include <dxgi1_2.h>
  4. #include <wrl/client.h> // 仅用于异常处理,不用于智能指针
  5. #include <iostream>

  6. #pragma comment(lib, "d3d11.lib")
  7. #pragma comment(lib, "dxgi.lib")

  8. #define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p) = nullptr; } }

  9. // 窗口尺寸
  10. const int WINDOW_WIDTH = 800;
  11. const int WINDOW_HEIGHT = 600;

  12. // 全局变量
  13. ID3D11Device* g_pD3DDevice = nullptr;
  14. ID3D11DeviceContext* g_pD3DDeviceContext = nullptr;
  15. IDXGIOutputDuplication* g_pDeskDupl = nullptr;
  16. ID3D11Texture2D* g_pAcquiredDesktopImage = nullptr;
  17. ID3D11Texture2D* g_pRenderTargetTexture = nullptr;
  18. ID3D11RenderTargetView* g_pRenderTargetView = nullptr;
  19. IDXGISwapChain* g_pSwapChain = nullptr;

  20. // 函数声明
  21. bool InitializeDirect3D(HWND hwnd);
  22. bool InitializeDesktopDuplication();
  23. void CaptureFrame();
  24. void RenderFrame();
  25. void Cleanup();

  26. // 窗口过程函数
  27. LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  28. {
  29.     switch (msg)
  30.     {
  31.     case WM_DESTROY:
  32.         PostQuitMessage(0);
  33.         return 0;
  34.     }
  35.     return DefWindowProc(hwnd, msg, wParam, lParam);
  36. }

  37. // 主函数
  38. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
  39. {
  40.     // 注册窗口类
  41.     WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hInstance, nullptr, nullptr, nullptr, nullptr, L"ScreenCaptureClass", nullptr };
  42.     RegisterClassEx(&wc);

  43.     // 创建窗口
  44.     HWND hwnd = CreateWindow(wc.lpszClassName, L"DirectX Desktop Duplication API Example", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, nullptr, nullptr, hInstance, nullptr);
  45.     if (!hwnd)
  46.     {
  47.         std::cerr << "Failed to create window!" << std::endl;
  48.         return -1;
  49.     }

  50.     ShowWindow(hwnd, nCmdShow);
  51.     UpdateWindow(hwnd);

  52.     // 初始化 Direct3D
  53.     if (!InitializeDirect3D(hwnd))
  54.     {
  55.         std::cerr << "Failed to initialize Direct3D!" << std::endl;
  56.         Cleanup();
  57.         return -1;
  58.     }

  59.     // 初始化桌面复制
  60.     if (!InitializeDesktopDuplication())
  61.     {
  62.         std::cerr << "Failed to initialize desktop duplication!" << std::endl;
  63.         Cleanup();
  64.         return -1;
  65.     }

  66.     // 主消息循环
  67.     MSG msg = { 0 };
  68.     while (msg.message != WM_QUIT)
  69.     {
  70.         if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
  71.         {
  72.             TranslateMessage(&msg);
  73.             DispatchMessage(&msg);
  74.         }
  75.         else
  76.         {
  77.             CaptureFrame();
  78.             RenderFrame();
  79.         }
  80.     }

  81.     Cleanup();
  82.     return static_cast<int>(msg.wParam);
  83. }

  84. // 初始化 Direct3D
  85. bool InitializeDirect3D(HWND hwnd)
  86. {
  87.     // 创建设备和交换链
  88.     DXGI_SWAP_CHAIN_DESC scd = {};
  89.     scd.BufferCount = 1;
  90.     scd.BufferDesc.Width = WINDOW_WIDTH;
  91.     scd.BufferDesc.Height = WINDOW_HEIGHT;
  92.     scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
  93.     scd.BufferDesc.RefreshRate.Numerator = 60;
  94.     scd.BufferDesc.RefreshRate.Denominator = 1;
  95.     scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
  96.     scd.OutputWindow = hwnd;
  97.     scd.SampleDesc.Count = 1;
  98.     scd.SampleDesc.Quality = 0;
  99.     scd.Windowed = TRUE;

  100.     HRESULT hr = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, nullptr, 0, D3D11_SDK_VERSION, &scd, &g_pSwapChain, &g_pD3DDevice, nullptr, &g_pD3DDeviceContext);
  101.     if (FAILED(hr))
  102.     {
  103.         std::cerr << "Failed to create device and swap chain!" << std::endl;
  104.         return false;
  105.     }

  106.     // 创建渲染目标视图
  107.     ID3D11Texture2D* pBackBuffer = nullptr;
  108.     hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&pBackBuffer));
  109.     if (FAILED(hr))
  110.     {
  111.         std::cerr << "Failed to get back buffer!" << std::endl;
  112.         return false;
  113.     }

  114.     hr = g_pD3DDevice->CreateRenderTargetView(pBackBuffer, nullptr, &g_pRenderTargetView);
  115.     SAFE_RELEASE(pBackBuffer);
  116.     if (FAILED(hr))
  117.     {
  118.         std::cerr << "Failed to create render target view!" << std::endl;
  119.         return false;
  120.     }

  121.     g_pD3DDeviceContext->OMSetRenderTargets(1, &g_pRenderTargetView, nullptr);

  122.     // 设置视口
  123.     D3D11_VIEWPORT vp = {};
  124.     vp.Width = static_cast<float>(WINDOW_WIDTH);
  125.     vp.Height = static_cast<float>(WINDOW_HEIGHT);
  126.     vp.MinDepth = 0.0f;
  127.     vp.MaxDepth = 1.0f;
  128.     vp.TopLeftX = 0;
  129.     vp.TopLeftY = 0;
  130.     g_pD3DDeviceContext->RSSetViewports(1, &vp);

  131.     return true;
  132. }

  133. // 初始化桌面复制
  134. bool InitializeDesktopDuplication()
  135. {
  136.     // 获取 DXGI 设备
  137.     IDXGIDevice* pDxgiDevice = nullptr;
  138.     HRESULT hr = g_pD3DDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&pDxgiDevice));
  139.     if (FAILED(hr))
  140.     {
  141.         std::cerr << "Failed to get DXGI device!" << std::endl;
  142.         return false;
  143.     }

  144.     // 获取 DXGI 适配器
  145.     IDXGIAdapter* pDxgiAdapter = nullptr;
  146.     hr = pDxgiDevice->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast<void**>(&pDxgiAdapter));
  147.     SAFE_RELEASE(pDxgiDevice);
  148.     if (FAILED(hr))
  149.     {
  150.         std::cerr << "Failed to get DXGI adapter!" << std::endl;
  151.         return false;
  152.     }

  153.     // 获取 DXGI 输出
  154.     IDXGIOutput* pDxgiOutput = nullptr;
  155.     hr = pDxgiAdapter->EnumOutputs(0, &pDxgiOutput);
  156.     SAFE_RELEASE(pDxgiAdapter);
  157.     if (FAILED(hr))
  158.     {
  159.         std::cerr << "Failed to get DXGI output!" << std::endl;
  160.         return false;
  161.     }

  162.     // 获取 DXGI 输出1
  163.     IDXGIOutput1* pDxgiOutput1 = nullptr;
  164.     hr = pDxgiOutput->QueryInterface(__uuidof(IDXGIOutput1), reinterpret_cast<void**>(&pDxgiOutput1));
  165.     SAFE_RELEASE(pDxgiOutput);
  166.     if (FAILED(hr))
  167.     {
  168.         std::cerr << "Failed to get DXGI output1!" << std::endl;
  169.         return false;
  170.     }

  171.     // 创建桌面复制接口
  172.     hr = pDxgiOutput1->DuplicateOutput(g_pD3DDevice, &g_pDeskDupl);
  173.     SAFE_RELEASE(pDxgiOutput1);
  174.     if (FAILED(hr))
  175.     {
  176.         std::cerr << "Failed to create desktop duplication interface!" << std::endl;
  177.         return false;
  178.     }

  179.     return true;
  180. }

  181. // 捕获桌面帧
  182. void CaptureFrame()
  183. {
  184.     DXGI_OUTDUPL_FRAME_INFO frameInfo;
  185.     IDXGIResource* pDesktopResource = nullptr;

  186.     // 获取桌面帧
  187.     HRESULT hr = g_pDeskDupl->AcquireNextFrame(0, &frameInfo, &pDesktopResource);
  188.     if (FAILED(hr))
  189.     {
  190.         if (hr == DXGI_ERROR_WAIT_TIMEOUT)
  191.         {
  192.             return; // 没有新的帧
  193.         }
  194.         std::cerr << "Failed to acquire next frame!" << std::endl;
  195.         return;
  196.     }

  197.     // 获取桌面纹理
  198.     hr = pDesktopResource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&g_pAcquiredDesktopImage));
  199.     SAFE_RELEASE(pDesktopResource);
  200.     if (FAILED(hr))
  201.     {
  202.         std::cerr << "Failed to get desktop texture!" << std::endl;
  203.         g_pDeskDupl->ReleaseFrame();
  204.         return;
  205.     }

  206.     // 释放帧
  207.     g_pDeskDupl->ReleaseFrame();
  208. }

  209. // 渲染帧
  210. void RenderFrame()
  211. {
  212.     if (!g_pAcquiredDesktopImage)
  213.     {
  214.         return;
  215.     }

  216.     // 创建渲染目标纹理
  217.     D3D11_TEXTURE2D_DESC desc;
  218.     g_pAcquiredDesktopImage->GetDesc(&desc);

  219.     if (!g_pRenderTargetTexture)
  220.     {
  221.         desc.Width = WINDOW_WIDTH;
  222.         desc.Height = WINDOW_HEIGHT;
  223.         desc.BindFlags = D3D11_BIND_RENDER_TARGET;
  224.         desc.MiscFlags = 0;

  225.         HRESULT hr = g_pD3DDevice->CreateTexture2D(&desc, nullptr, &g_pRenderTargetTexture);
  226.         if (FAILED(hr))
  227.         {
  228.             std::cerr << "Failed to create render target texture!" << std::endl;
  229.             return;
  230.         }
  231.     }

  232.     // 将桌面图像复制到渲染目标纹理
  233.     g_pD3DDeviceContext->CopyResource(g_pRenderTargetTexture, g_pAcquiredDesktopImage);

  234.     // 清除渲染目标
  235.     float clearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
  236.     g_pD3DDeviceContext->ClearRenderTargetView(g_pRenderTargetView, clearColor);

  237.     // 渲染纹理到窗口
  238.     g_pD3DDeviceContext->OMSetRenderTargets(1, &g_pRenderTargetView, nullptr);
  239.     g_pD3DDeviceContext->Draw(4, 0);

  240.     // 呈现交换链
  241.     g_pSwapChain->Present(0, 0);

  242.     // 释放桌面图像
  243.     SAFE_RELEASE(g_pAcquiredDesktopImage);
  244. }

  245. // 清理资源
  246. void Cleanup()
  247. {
  248.     SAFE_RELEASE(g_pRenderTargetTexture);
  249.     SAFE_RELEASE(g_pRenderTargetView);
  250.     SAFE_RELEASE(g_pSwapChain);
  251.     SAFE_RELEASE(g_pDeskDupl);
  252.     SAFE_RELEASE(g_pD3DDeviceContext);
  253.     SAFE_RELEASE(g_pD3DDevice);
  254. }
复制代码





欢迎光临 递归火山软件开发平台 (https://bbs.voldp.com/) Powered by Discuz! X3.4