提问人:c00000fd 提问时间:9/8/2023 更新时间:9/10/2023 访问量:87
RESOURCE_MANIPULATION 调用 ID3D11DeviceContext::CopySubresourceRegion 从网络摄像头呈现视频时出现错误 #281
RESOURCE_MANIPULATION ERROR #281 when calling ID3D11DeviceContext::CopySubresourceRegion to render video from a webcam
问:
我正在尝试重写我的纯软件逻辑,以显示来自网络摄像头的视频源。这次使用硬件和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]
我不知道这是什么意思。
关于如何解决这个问题的任何帮助?
答:
正如系统告诉你的那样,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
评论
DXGI_FORMAT_B8G8R8X8_UNORM
DXGI_FORMAT_B8G8R8A8_UNORM
D3D11_VIEWPORT
评论
GetDesc
g_pHW_BackBuffer
com_Texture
CopySubresourceRegion
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;}
DXGI_FORMAT_B8G8R8X8_UNORM
D3D11CreateDeviceAndSwapChain
E_INVALIDARG
D3D11CreateDeviceAndSwapChain