C++使用DirectX11捕获屏幕

332nm8kg  于 2024-01-09  发布在  其他
关注(0)|答案(1)|浏览(194)

我尝试在C++中使用DirectX 11来捕获屏幕并将其转换为我可以使用OpenGL或ImGui渲染的纹理。我使用了Windows API和BitBlt,但这导致fps低于15,所以这不是一个选项。
我使用的是Windows 11,带有Nvidia显卡。
库导入:

  1. #pragma comment(lib, "dxgi.lib")
  2. #pragma comment(lib, "d3d11.lib")

字符串
正在初始化DirectX 11:

  1. bool DirectX11::initDirectX11() {
  2. HRESULT hr = S_OK;
  3. IDXGIFactory* DXGIFactory = nullptr;
  4. IDXGIAdapter* Adapter = nullptr;
  5. D3D_FEATURE_LEVEL FeatureLevel = D3D_FEATURE_LEVEL_11_0;
  6. Output = nullptr;
  7. deskDupl = nullptr;
  8. hr = CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)(&DXGIFactory));
  9. if (FAILED(hr)) {
  10. std::cout << "Failed to create DXGI Factory" << std::endl;
  11. return false;
  12. }
  13. hr = DXGIFactory->EnumAdapters(0, &Adapter);
  14. if (FAILED(hr)) {
  15. std::cout << "Failed to create adapter" << std::endl;
  16. return false;
  17. }
  18. hr = Adapter->EnumOutputs(0, &Output);
  19. if (FAILED(hr)) {
  20. std::cout << "Failed to create output" << std::endl;
  21. return false;
  22. }
  23. hr = Output->QueryInterface(__uuidof(Output), (void**)(&deskDupl));
  24. if (FAILED(hr)) {
  25. std::cout << "Failed to create output1" << std::endl;
  26. return false;
  27. }
  28. hr = Output->GetDesc(&OutputDesc);
  29. if (FAILED(hr)) {
  30. std::cout << "Failed to get output description" << std::endl;
  31. return false;
  32. }
  33. hr = D3D11CreateDevice(Adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, 0, NULL, 0, D3D11_SDK_VERSION, &device, &FeatureLevel, &deviceContext);
  34. if (FAILED(hr)) {
  35. std::cout << "Failed to create D3D11 device" << std::endl;
  36. return false;
  37. }
  38. DXGIFactory->Release();
  39. Adapter->Release();
  40. return true;
  41. }


捕获屏幕:

  1. void DirectX11::captureScreen() {
  2. HRESULT hr = S_OK;
  3. IDXGIResource* DesktopResource;
  4. DXGI_OUTDUPL_FRAME_INFO FrameInfo;
  5. // Get new frame
  6. hr = deskDupl->AcquireNextFrame(500, &FrameInfo, &DesktopResource);
  7. if (FAILED(hr)) {
  8. std::cout << "Failed to acquire next frame" << std::endl;
  9. return;
  10. }
  11. // Store the frame as a texture
  12. // Trows exception
  13. // Read access violation
  14. // DesktopResource was 0xFFFFFFFFFFFFFFFF
  15. hr = DesktopResource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&AcquiredDesktopImage));
  16. if (FAILED(hr)) {
  17. std::cout << "Failed to query interface" << std::endl;
  18. return;
  19. }
  20. }


问题是它不断抛出读访问冲突异常。

  1. Read access violation
  2. DesktopResource was 0xFFFFFFFFFFFFFFFF

nsc4cvqm

nsc4cvqm1#

此代码

  1. hr = Output->QueryInterface(__uuidof(Output), (void**)(&deskDupl));

字符串
无效,因为它将IDXGIOutput引用写入IDXGIOutputDuplication引用。
要获取IDXGIOutputDuplication引用,必须调用IDXGIOutput1::DuplicateOutput method,因此必须先获取IDXGIOutput1,如下所示:

  1. IDXGIOutput1* o1;
  2. hr = Output->QueryInterface(__uuidof(IDXGIOutput1), (void**)(&o1));


然后

  1. hr = o1->DuplicateOutput(device, &deskDupl);


但要成功执行此操作,您必须从IDXGIFactory1或从CreateDXGIFactory1(DXGI 1.1)创建的IDXGIFactory工厂创建设备,因此将调用CreateDXGIFactory替换为CreateDXGIFactory1
注意事项:为了避免对QueryInterface和许多其他COM调用进行危险的(void**)转换,从而避免在使用Visual Studio时发生原始转换错误(至少部分错误),您可以使用IID_PPV_ARGS宏。因此,您可以编写以下内容:

  1. hr = Output->QueryInterface(IID_PPV_ARGS(&o1));


现在,IUnknown定义头文件(Windows SDK的Unknwnbase.h)也定义了一些更有用的C++模板,所以你甚至可以直接调用QueryInterface:

  1. hr = Output->QueryInterface(&o1);


PS:注意确保这存在于MSVC以外的其他编译器中。

展开查看全部

相关问题