如何在win7上将ID3D11Texture2D内容复制到IMFSample?
Posted
技术标签:
【中文标题】如何在win7上将ID3D11Texture2D内容复制到IMFSample?【英文标题】:How to copy ID3D11Texture2D content to IMFSample on win7? 【发布时间】:2020-10-27 14:40:26 【问题描述】:在win8及以上,我可以直接使用MFCreateDXGISurfaceBufferWrapper,但是在Win7系统上不支持这个接口,所以只能复制到CPU上(“_capture_texture_2D”是在Win7上用D3D11_USAGE_STAGING创建的)但是最终显示的图像是斜。感觉转换结果的长宽不正确:
_capture_texture2d 是为与 DXGI_FORMAT_B8G8R8A8_UNORM 进行 d2d 互操作而创建的,但 MFVideoFormat_XXX 没有看到对应的格式
也许“锁定”需要音高支持,但我找不到介绍
HRESULT hr = E_NOTIMPL;
CComPtr<IMFMediaBuffer> media_buffer;
if (IsWindows8OrGreater())
hr = MFCreateDXGISurfaceBufferWrapper(__uuidof(ID3D11Texture2D), _capture_texture2d, 0, FALSE, &media_buffer);
CComPtr<IMF2DBuffer> twod_buffer;
hr = media_buffer->QueryInterface(&twod_buffer);
RETURN_ON_FAIL(hr);
DWORD length = 0;
hr = twod_buffer->GetContiguousLength(&length);
RETURN_ON_FAIL(hr);
hr = media_buffer->SetCurrentLength(length);
RETURN_ON_FAIL(hr);
else
D3D11_TEXTURE2D_DESC desc;
_capture_texture2d->GetDesc(&desc);
UINT32 img_size = 0;
hr = MFCalculateImageSize(MFVideoFormat_RGB32, desc.Width, desc.Height, &img_size);
RETURN_ON_FAIL(hr);
D3D11_MAPPED_SUBRESOURCE resource;
UINT subresource = D3D11CalcSubresource(0, 0, 0);
hr = immediate_context->Map(_capture_texture2d, subresource, D3D11_MAP_READ, 0, &resource);
RETURN_ON_FAIL(hr);
hr = MFCreateMemoryBuffer(img_size, &media_buffer);
if (SUCCEEDED(hr))
BYTE *dst = NULL;
hr = media_buffer->Lock(&dst, NULL, NULL);
if (SUCCEEDED(hr))
BYTE* src = (BYTE*)resource.pData;
for (size_t i = 0; i < desc.Height; i++)
memcpy(dst, src, desc.Width * 4);
src += resource.RowPitch;
dst += desc.Width * 4;
media_buffer->Unlock();
immediate_context->Unmap(_capture_texture2d, subresource);
RETURN_ON_FAIL(hr);
hr = media_buffer->SetCurrentLength(img_size);
RETURN_ON_FAIL(hr);
CComPtr<IMFSample> sample;
hr = MFCreateSample(sample);
RETURN_ON_FAIL(hr);
hr = sample->AddBuffer(media_buffer);
RETURN_ON_FAIL(hr);
【问题讨论】:
【参考方案1】:使用函数MFGetStrideForBitmapInfoHeader和MFCopyImage解决:
D3D11_TEXTURE2D_DESC desc;
_capture_texture2d->GetDesc(&desc);
UINT32 img_size = 0;
GUID dst_format = MFVideoFormat_RGB32;
hr = MFCalculateImageSize(dst_format, desc.Width, desc.Height, &img_size);
RETURN_ON_FAIL(hr);
LONG dst_stride = 0;
hr = MFGetStrideForBitmapInfoHeader(dst_format.Data1, desc.Width, &dst_stride);
RETURN_ON_FAIL(hr);
D3D11_MAPPED_SUBRESOURCE resource;
UINT subresource = D3D11CalcSubresource(0, 0, 0);
hr = immediate_context->Map(_capture_texture2d, subresource, D3D11_MAP_READ, 0, &resource);
RETURN_ON_FAIL(hr);
hr = MFCreateMemoryBuffer(img_size, &media_buffer);
if (SUCCEEDED(hr))
BYTE *dst_data = NULL;
hr = media_buffer->Lock(&dst_data, NULL, NULL);
if (SUCCEEDED(hr))
if (dst_stride >= 0)
hr = MFCopyImage(dst_data, dst_stride, (BYTE*)resource.pData, resource.RowPitch, desc.Width * 4, desc.Height);
else
BYTE *src_ptr = (BYTE*)resource.pData;
BYTE *dst_ptr = dst_data - dst_stride * (desc.Height - 1);
size_t copy_bytes = min(resource.RowPitch, (UINT)-dst_stride);
for (size_t i = 0; i < desc.Height; i++)
memcpy(dst_ptr, src_ptr, copy_bytes);
src_ptr += resource.RowPitch;
dst_ptr += dst_stride;
media_buffer->SetCurrentLength(img_size);
media_buffer->Unlock();
immediate_context->Unmap(_capture_texture2d, subresource);
...
【讨论】:
以上是关于如何在win7上将ID3D11Texture2D内容复制到IMFSample?的主要内容,如果未能解决你的问题,请参考以下文章
ID3D11Texture2D 到 ID2D1Bitmap,可以吗?
DirectX:以 DXGI_FORMAT_NV12 格式从 ID3D11Texture2D 获取 RGB 数据的最佳方法?