支持D3D11硬件加速的FFMPEG:如何将DirectX纹理复制到OpenGL?

bqf10yzr  于 2022-11-04  发布在  其他
关注(0)|答案(1)|浏览(569)

我正在使用FFMPEG和D3 D11视频加速对视频进行解码。我希望在GUI中显示解码后的帧,为了避免将解码后的帧复制回系统内存,我的目标是将从FFMPEG中得到的ID 3D 11 Texture 2D直接复制/Map到OpenGL纹理中,为此,有一个OpenGL扩展(WGL_NV_DX_互操作性和WGL_NV_DX_互操作性2)。
但是,我没有让它运行起来。下面是我目前为止的代码(精简):

// create texture, to be used later in DirectX
GLuint texture_opengl;
glGenTextures(1, &texture_opengl);
// .. and set the usual parameters for it

// setup WGL_NV_DX_interop extension
AVBufferRef* hw_device_ctx_buffer = decoder_ctx->hw_device_ctx;
AVHWDeviceContext* hw_device_ctx = (AVHWDeviceContext*)hw_device_ctx_buffer->data;
AVD3D11VADeviceContext* hw_d3d11_dev_ctx = (AVD3D11VADeviceContext*)hw_device_ctx->hwctx;
HANDLE device_handle = wglDXOpenDeviceNV(hw_d3d11_dev_ctx->device);

// create intermediate texture
D3D11_TEXTURE2D_DESC pDes{};
ZeroMemory(&pDes, sizeof(pDes));
pDes.Width = frame->width;
pDes.Height = frame->height;
pDes.ArraySize = 1;
pDes.MipLevels = 1;
pDes.Format = DXGI_FORMAT_NV12;
pDes.SampleDesc.Count = 1;
pDes.SampleDesc.Quality = 0;
pDes.Usage = D3D11_USAGE_DEFAULT;
pDes.BindFlags = D3D11_BIND_UNORDERED_ACCESS;
pDes.CPUAccessFlags = 0;
pDes.MiscFlags = 0;

ID3D11Texture2D* texture_D3D11;
hw_d3d11_dev_ctx->device->CreateTexture2D(&pDes, NULL, &texture_D3D11);

// connect opengl and directx textures
HANDLE hRegisterObject = wglDXRegisterObjectNV(
    device_handle, texture_D3D11, texture_opengl, GL_TEXTURE_2D, WGL_ACCESS_READ_WRITE_NV
        );

// run loop and display video
while(..)
{
  // read packets from video file and send it to decoder  

  // receive frame from decoder
  avcodec_receive_frame(decoder_ctx, frame);

  // get DirectX objects from frame
  ID3D11Texture2D* hwTexture = (ID3D11Texture2D*)frame->data[0];
  intptr_t texture_array_index = (intptr_t)frame->data[1];

  // copy frame texture to intermediate texture
  hw_d3d11_dev_ctx->device_context->CopySubresourceRegion(
        texture_D3D11, 0, 0, 0, 0,
        hwTexture, texture_array_index,
        NULL
  );

}

在将FFMPEG帧的内容复制到我的中间纹理texture_directx之后,我希望我可以用OpenGL纹理texture_opengl显示数据。但是,这个纹理是空的。我也没有在GPU的资源监视器中看到任何复制活动。
有没有人做过这件事,或者可能会看到我的方法中的错误?
我没有考虑处理NV 12格式。现在,我只需要复制帧的亮度部分就足够了。

kmynzznz

kmynzznz1#

(Too我很想发表评论。而且太晚了。但也许你可以为后代报道其中的一些。)
你试过这些吗?

  • 使能debug layers in Direct3D11
  • 将通过其他方法(Map/上传、渲染、着色器写入)获得的ID3D11Texture2D复制到OpenGL。如果此操作有效,请查看下一项。
  • 也许你从FFmpeg得到的ID3D11Texture2D缺少一些必要的标志。FFmpeg在hwcontext_d3d11va.c中创建ID3D11Texture2D(包括单精度和数组,但你已经在处理数组纹理了),其中
.Usage      = D3D11_USAGE_DEFAULT,
 .BindFlags  = D3D11_BIND_DECODER,   //probably?
 .MiscFlags  = 0,  //probably?
  • 验证您是否符合所有CopySubresourceRegion()。包括“必须具有兼容的DXGI格式[...]"。如果不符合,复制将失败;检查错误的返回值。调试层将告诉您详细信息!
  • 对于pSrcBox,请尝试使用一些D3D11_BOX,而不是NULL
  • 请尝试CopyResource()而不是CopySubresourceRegion()

相关问题