RESOURCE_MANIPULATION 调用 ID3D11DeviceContext::CopySubresourceRegion 从网络摄像头呈现视频时出现错误 #281

RESOURCE_MANIPULATION ERROR #281 when calling ID3D11DeviceContext::CopySubresourceRegion to render video from a webcam

提问人:c00000fd 提问时间:9/8/2023 更新时间:9/10/2023 访问量:87

问:

我正在尝试重写我的纯软件逻辑,以显示来自网络摄像头的视频源。这次使用硬件和DirectX。(我需要先说这是我第一次为 DirectX 写东西。

我在全球范围内宣布了以下内容:

IMFMediaSource* g_pMediaSource = NULL;
ReaderCallback* gpRdrCallback = NULL;
IMFSourceReader* g_pSrcReader = NULL;

//DirectX stuff:
IDXGISwapChain1* g_pHW_SwapChain = NULL;               
ID3D11Device1* g_pHW_D3DDevice = NULL;                 
ID3D11DeviceContext1* g_pHW_ImmContext = NULL;         
IMFDXGIDeviceManager* g_pHW_DXGIDevMgr = NULL;         
ID3D11RenderTargetView* g_pHW_RenderTargetView = NULL; 
ID3D11Texture2D* g_pHW_BackBuffer = NULL;  

我得到网络摄像头,在应用程序启动时使用此代码:IMFMediaSource

//Error handling is omitted for readability
CComPtr<IMFAttributes> com_attributes;
hr = MFCreateAttributes(&com_attributes, 2);

hr = com_attributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
                             MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);

hr = com_attributes->SetString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, 
                               strWebcamSymLink.c_str());

CComPtr<IMFActivate> com_Activ;
hr = MFCreateDeviceSourceActivate(com_attributes, &com_Activ);

hr = com_Activ->ActivateObject(IID_PPV_ARGS(&g_pMediaSource));

然后,我在初始化期间执行以下操作(一次)以设置 DirectX:

(为了便于阅读,省略了错误处理。

//For this test, the input parameters are:
//(As they are received from a webcam)
//
//  szFrameW = 160;
//  szFrameH = 90;
//  nFrameRateNumer = 5;
//  nFrameRateDenom = 1;
//  nAspectRatioNumer = 1;
//  nAspectRatioDenom = 1;
//  dwIdxDev = 0;            //Webcam device index
//

DXGI_SWAP_CHAIN_DESC sd = {};

sd.BufferCount = 1;

sd.BufferDesc.Width = szFrameW;
sd.BufferDesc.Height = szFrameH;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE;
sd.BufferDesc.Scaling = DXGI_MODE_SCALING_CENTERED;
sd.BufferDesc.RefreshRate.Numerator = nFrameRateNumer;
sd.BufferDesc.RefreshRate.Denominator = nFrameRateDenom;

sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;

sd.OutputWindow = ghWnd;       //Main window handle
sd.Windowed = TRUE;

sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;


D3D_FEATURE_LEVEL d3dFeatureLvls[] = {
    D3D_FEATURE_LEVEL_11_1,
};

UINT dwNumLvlsRequested = _countof(d3dFeatureLvls);

D3D_FEATURE_LEVEL FeatureLevelsSupported;

CComPtr<IDXGISwapChain> com_SwapChain;
CComPtr<ID3D11Device> com_Dev;
CComPtr<ID3D11DeviceContext> com_Ctx;

hr = D3D11CreateDeviceAndSwapChain(NULL, 
    D3D_DRIVER_TYPE_HARDWARE, 
    NULL, 
    D3D11_CREATE_DEVICE_BGRA_SUPPORT |
#ifdef _DEBUG
    D3D11_CREATE_DEVICE_DEBUG
#else
    0
#endif
    ,
    d3dFeatureLvls, 
    dwNumLvlsRequested, 
    D3D11_SDK_VERSION, 
    &sd, 
    &com_SwapChain, 
    &com_Dev, 
    &FeatureLevelsSupported,
    &com_Ctx);

//Get version 1.0 of interfaces - I'm not sure if I need it here?
hr = com_SwapChain.QueryInterface(&g_pHW_SwapChain);
hr = com_Dev.QueryInterface(&g_pHW_D3DDevice);
hr = com_Ctx.QueryInterface(&g_pHW_ImmContext);

hr = g_pHW_SwapChain->GetBuffer(0, IID_PPV_ARGS(&g_pHW_BackBuffer));

hr = g_pHW_D3DDevice->CreateRenderTargetView(g_pHW_BackBuffer, NULL, &g_pHW_RenderTargetView);

g_pHW_ImmContext->OMSetRenderTargets(1, &g_pHW_RenderTargetView, NULL);

D3D11_VIEWPORT vp;
vp.Width = (FLOAT)szFrameW;
vp.Height = (FLOAT)szFrameH;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;

g_pHW_ImmContext->RSSetViewports( 1, &vp );

CComPtr<IMFTransform> com_Transform;
hr = g_pMediaSource->QueryInterface(IID_PPV_ARGS(&com_Transform));

UINT uiToken = 0;
hr = MFCreateDXGIDeviceManager(&uiToken, &g_pHW_DXGIDevMgr);

hr = g_pHW_DXGIDevMgr->ResetDevice(g_pHW_D3DDevice, uiToken);

hr = com_Transform->ProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER, 
                                   (ULONG_PTR)g_pHW_DXGIDevMgr);

然后,要启动 Microsoft 媒体基础以从网络摄像机进行异步呈现:

//Error handling is omitted for readability

hr = MFCreateAttributes(&com_attributes, 3);

gpRdrCallback = new ReaderCallback();
hr = com_attributes->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, gpRdrCallback);

hr = com_attributes->SetUINT32(MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, TRUE);
hr = com_attributes->SetUINT32(MF_SOURCE_READER_DISCONNECT_MEDIASOURCE_ON_SHUTDOWN, TRUE);
hr = com_attributes->SetUnknown(MF_SOURCE_READER_D3D_MANAGER, g_pHW_DXGIDevMgr);

hr = MFCreateSourceReaderFromMediaSource(g_pMediaSource, com_attributes, &g_pSrcReader);

CComPtr<IMFMediaType> com_vid_output;
hr = MFCreateMediaType(&com_vid_output);

hr = com_vid_output->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
hr = com_vid_output->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32);
hr = com_vid_output->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
hr = com_vid_output->SetUINT64(MF_MT_FRAME_SIZE, 
                               PackSize(szFrameW, szFrameH));

hr = com_vid_output->SetUINT64(MF_MT_FRAME_RATE, 
                               PackSize(nFrameRateNumer, nFrameRateDenom));

hr = MFSetAttributeRatio(com_vid_output,
    MF_MT_PIXEL_ASPECT_RATIO,
    nAspectRatioNumer,
    nAspectRatioDenom);

hr = g_pSrcReader->SetCurrentMediaType(dwIdxDev, NULL, com_vid_output);

//Initiate the read from a webcam (async)
hr = g_pSrcReader->SetStreamSelection(dwIdxDev, TRUE);
hr = g_pSrcReader->ReadSample(dwIdxDev,
                              0,
                              NULL, NULL, NULL, NULL);

在那之后,当我读取一帧时:ReaderCallback

//Error handling is omitted for readability

HRESULT ReaderCallback::OnReadSample(HRESULT hrStatus, 
                                     DWORD dwStreamIndex,
                                     DWORD dwStreamFlags,
                                     LONGLONG llTimestamp,
                                     IMFSample* pSample)
{
    if(SUCCEEDED(hrStatus))
    {
        CComPtr<IMFMediaBuffer> com_buffer;
        hr = pSample->ConvertToContiguousBuffer(&com_buffer);

        com_buffer->AddRef();   /pseudo-call
        remember_video_buffer_for_later_processing(com_buffer);
        
    }

    //Initiate reading of another frame
    hr = g_pSrcReader->ReadSample(dwIdxDev,
                              0,
                              NULL, NULL, NULL, NULL);

    return S_OK;
}

最后,当我准备好将视频帧渲染到窗口上时: (框架是从我的上面收到的。ReaderCallback::OnReadSample

//Error handling is omitted for readability

void renderFromRawVideoPixels(IMFMediaBuffer* pMediaBuffer)
{
    CComPtr<IMFDXGIBuffer> com_DxgBuffer;
    hr = pMediaBuffer->QueryInterface(IID_PPV_ARGS(&com_DxgBuffer));

    CComPtr<ID3D11Texture2D> com_Texture;
    hr = com_DxgBuffer->GetResource(IID_PPV_ARGS(&com_Texture));

    UINT nSubindex;
    hr = com_DxgBuffer->GetSubresourceIndex(&nSubindex);

    g_pHW_ImmContext->CopySubresourceRegion(g_pHW_BackBuffer,
        0, 0 ,0, 0,
        com_Texture,
        nSubindex,
        NULL);

    DXGI_PRESENT_PARAMETERS dpp = {};
    hr = g_pHW_SwapChain->Present1(0, 0, &dpp);
}

对上面的调用在调试输出窗口中留下了以下错误,并且出现黑屏:g_pHW_ImmContext->CopySubresourceRegion

D3D11 错误:ID3D11DeviceContext::CopySubresourceRegion:无法调用 CopySubresourceRegion,当每个 Resource 的 Formats 不是 相同或至少可相互浇铸,除非一种格式是 压缩(DXGI_FORMAT_R9G9B9E5_SHAREDEXP,或 DXGI_FORMAT_BC[1,2,3,4,5,6,7]_* ),源格式类似于 根据:BC[1|4] ~= R16G16B16A16|R32G32,BC[2|3|5|6|7] ~= R32G32B32A32,R9G9B9E5_SHAREDEXP ~= R32。[ RESOURCE_MANIPULATION 错误 #281:COPYSUBRESOURCEREGION_INVALIDSOURCE]

我不知道这是什么意思。

关于如何解决这个问题的任何帮助?

C++ directx ms-media-foundation direct3d11 dxgi

评论

1赞 Roman R. 9/8/2023
我想说的是,如果您在调用之后和之前调用这些资源,您将能够看到它们与复制操作的不兼容程度。GetDescg_pHW_BackBuffercom_TextureCopySubresourceRegion
0赞 c00000fd 9/8/2023
@RomanR。如果它们不兼容,有什么方法可以将它们从一个转换为另一个?
0赞 c00000fd 9/8/2023
这是区别。的 : ,而 :com_Texture{format=DXGI_FORMAT_B8G8R8X8_UNORM; BindFlags=D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE}g_pHW_BackBuffer{format=DXGI_FORMAT_R8G8B8A8_UNORM; BindFlags=D3D11_BIND_RENDER_TARGET;}
0赞 Roman R. 9/8/2023
这两种资源都是 32 bpp,但格式仍然不同B8G8R8X8_UNORM R8G8B8A8_UNORM。无论如何,您绝对不想将BGR复制到RGB。您希望在那里拥有兼容的格式,最简单的可能是使用将要兼容的格式创建交换链。
0赞 c00000fd 9/8/2023
@RomanR。我刚刚试过。首先,当我指定对它的调用时,返回 .但即使成功了,我从哪里获得要输入的格式?它不依赖于网络摄像头吗?DXGI_FORMAT_B8G8R8X8_UNORMD3D11CreateDeviceAndSwapChainE_INVALIDARGD3D11CreateDeviceAndSwapChain

答:

2赞 Simon Mourier 9/10/2023 #1

正如系统告诉你的那样,Media Foundation 返回的格式与 DirectX 交换链期望的格式之间的格式不兼容。

您可以通过以下两项更改使它们兼容:

A)更改交换链格式,更改此:

sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;

进入这个:

sd.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;

B)更改MF输出视频格式,更改此:

hr = com_vid_output->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32);
=> MF will give you back DXGI_FORMAT_B8G8R8X8_UNORM

进入这个:

hr = com_vid_output->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_ARGB32);
=> MF will give you back DXGI_FORMAT_B8G8R8A8_UNORM

评论

0赞 c00000fd 9/11/2023
谢谢。但是哦,哇,说真的。这就是它🤦 ♂️的问题所在,我确实尝试更改格式,但选择了.DXGI_FORMAT_B8G8R8X8_UNORMDXGI_FORMAT_B8G8R8A8_UNORM
0赞 c00000fd 9/11/2023
如果您不介意,请跟进。但是,为什么它要将其拉伸到整个窗口的大小?我没有指定 to 是框架的大小吗?D3D11_VIEWPORT
1赞 Simon Mourier 9/11/2023
它不仅是交换链格式,而且本质上是 MF 输出格式。跟进:不确定您是否可以使用这样创建的窗换链来做到这一点。您可以改用 CreateSwapChainForHwnd 创建它 (并使用 D3D11CreateDevice 创建设备) ,如下所示 pastebin.com/raw/3a2Gg8v3 PS:您的呈现目标视图在这里无用(您基本上只需要一个 DXGI 图面),可以删除 CreateRenderTargetView OMSetRenderTargets 和 RSSetViewports。