如何在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 数据的最佳方法?

C#texture2d如何转换为cpu图像

D3D11:从 6 个图像创建立方体贴图

MF SinkWriter 写入样本失败

ID3D11VideoDevice::CreateVideoDecoderOutputView 失败