C++使用DirectX11捕获屏幕

332nm8kg  于 9个月前  发布在  其他
关注(0)|答案(1)|浏览(133)

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

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

字符串
正在初始化DirectX 11:

bool DirectX11::initDirectX11() {
        HRESULT hr = S_OK;
        IDXGIFactory* DXGIFactory = nullptr;
        IDXGIAdapter* Adapter = nullptr;
        D3D_FEATURE_LEVEL FeatureLevel = D3D_FEATURE_LEVEL_11_0;
        Output = nullptr;
        deskDupl = nullptr;

        hr = CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)(&DXGIFactory));
        if (FAILED(hr)) {
            std::cout << "Failed to create DXGI Factory" << std::endl;
            return false;
        }

        hr = DXGIFactory->EnumAdapters(0, &Adapter);
        if (FAILED(hr)) {
            std::cout << "Failed to create adapter" << std::endl;
            return false;
        }

        hr = Adapter->EnumOutputs(0, &Output);
        if (FAILED(hr)) {
            std::cout << "Failed to create output" << std::endl;
            return false;
        }

        hr = Output->QueryInterface(__uuidof(Output), (void**)(&deskDupl));
        if (FAILED(hr)) {
            std::cout << "Failed to create output1" << std::endl;
            return false;
        }

        hr = Output->GetDesc(&OutputDesc);
        if (FAILED(hr)) {
            std::cout << "Failed to get output description" << std::endl;
            return false;
        }

        hr = D3D11CreateDevice(Adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, 0, NULL, 0, D3D11_SDK_VERSION, &device, &FeatureLevel, &deviceContext);
        if (FAILED(hr)) {
            std::cout << "Failed to create D3D11 device" << std::endl;
            return false;
        }

        DXGIFactory->Release();
        Adapter->Release();
        return true;
    }


捕获屏幕:

void  DirectX11::captureScreen() {
        HRESULT hr = S_OK;

        IDXGIResource* DesktopResource;
        DXGI_OUTDUPL_FRAME_INFO FrameInfo;

        // Get new frame
        hr = deskDupl->AcquireNextFrame(500, &FrameInfo, &DesktopResource);
        if (FAILED(hr)) {
            std::cout << "Failed to acquire next frame" << std::endl;
            return;
        }

        
        // Store the frame as a texture
        // Trows exception
        // Read access violation
        // DesktopResource was 0xFFFFFFFFFFFFFFFF   
        hr = DesktopResource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&AcquiredDesktopImage));
        if (FAILED(hr)) {
            std::cout << "Failed to query interface" << std::endl;
            return;
        }

    }


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

Read access violation
DesktopResource was 0xFFFFFFFFFFFFFFFF

nsc4cvqm

nsc4cvqm1#

此代码

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

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

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


然后

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


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

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


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

hr = Output->QueryInterface(&o1);


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

相关问题