使用 NvPipe 编码桌面复制 API ID3D11Texture2D 帧

Encoding Desktop Duplication API ID3D11Texture2D frame using NvPipe

本文关键字:API ID3D11Texture2D 复制 桌面 NvPipe 编码 使用      更新时间:2023-10-16

我正在尝试使用桌面复制API捕获桌面帧,并立即使用NvPipe对其进行编码,而无需通过CPU访问像素。

有没有办法将ID3D11Texture2D数据作为NvPipe的输入,或者其他一些有效的方法?我正在研究一种需要尽可能低延迟的VR解决方案,因此即使节省1ms也是一件大事。

编辑:在遵循@Soonts的建议后,我最终得到了这段似乎不起作用的代码:

    cudaArray *array;
    m_DeviceContext->CopySubresourceRegion(CopyBuffer, 0, 0, 0, 0, m_SharedSurf, 0, Box);
    cudaError_t err = cudaGraphicsD3D11RegisterResource(&_cudaResource, CopyBuffer, cudaGraphicsRegisterFlagsNone);
    err = cudaGraphicsResourceSetMapFlags(_cudaResource, cudaGraphicsMapFlagsReadOnly);
    cudaStream_t cuda_stream;
    cudaStreamCreate(&cuda_stream);
    err = cudaGraphicsMapResources(1, &_cudaResource, cuda_stream);
    err = cudaGraphicsSubResourceGetMappedArray(&array, _cudaResource, 0, 0);
    uint64_t compressedSize = NvPipe_Encode(encoder, array, dataPitch, buffer.data(), buffer.size(), width, height, false);

该NvPipe_Encode会导致内存访问冲突,并且不执行任何操作。我不知道我搞砸了哪一步,因为我似乎无法在线找到有关任何函数或变量/结构的任何文档,并且将手表放在变量上除了它们在内存中的地址之外没有显示有价值的信息。

我没有

尝试过,但我认为应该可以通过 CUDA 互操作来实现。

调用 cudaGraphicsD3D11RegisterResource 为 CUDA 互操作注册纹理。不确定是否可以注册从 DD 获取的 DWM 拥有的纹理。如果不能,请创建另一个(在默认池中(,注册该帧,并使用 ID3D11DeviceContext::CopyResource 更新每个帧。

调用 cudaGraphicsResourceSetMapFlags 以指定您希望从互操作的 CUDA 端进行只读访问。

调用cudaGraphicsMapResources以允许 CUDA 访问纹理。

呼叫cudaGraphicsSubResourceGetMappedArray 。现在,您有一个设备指针,其中包含可以提供给NvPipe的帧数据。

附言另一种选择是使用媒体基础而不是NvPipe。适用于所有GPU,而不仅仅是nVidia,在大多数系统上MF也使用硬件编码器。我不确定延迟,从未将MF用于对它太敏感的事情,也从未使用过NvPipe,不知道它们如何比较。