我正在尝试重写我的纯软件逻辑,用于显示来自网络摄像头的视频源。这次使用硬件和 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 Media Foundation 以从网络摄像头进行异步渲染:
//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 当每个资源的 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。 [资源操作 错误 #281:COPYSUBRESOURCEREGION_INVALIDSOURCE]
我不知道这意味着什么。
有关于如何解决这个问题的帮助吗?
正如系统告诉您的那样,媒体基金会返回给您的格式与 DirectX 交换链期望的格式之间的格式。
您可以使它们兼容两项更改:
A)更改此:
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
进入这个:
sd.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
B)改变这个:
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