在CaptureGraphBuilder2中使用SampleGrabber时出现的问题
Problems Using SampleGrabber with CaptureGraphBuilder2
我一直在尝试使用SampleGrabber从网络摄像头中获取帧并将其保存为位图,但没有成功。我在MSDN上使用了Directshow视频捕获示例,使用ICaptureGraphBuilder2以及Sample grabber示例。
我希望我的过滤图看起来如下:
网络摄像头(来源)->采样采集器->空渲染器
由于我对预览不感兴趣,我决定空渲染器对我来说就足够了
计划是通过搜索特定的VID和PID(webcamCapture::findWebCam())来找到我的网络摄像头,创建我的采样器,创建空渲染器,然后使用pGraphBuilder->RenderStream()将它们连接在一起。由于我只需要一个帧,所以我使用OneShot方法,然后使用GetCurrentBuffer来检索帧。
问题发生在这一行:
pEvent->WaitForCompletion(2000, &evCode);
返回的HRESULT代码为E_ABORT。将超时设置为INFINITE会导致程序冻结,这可能意味着过滤器永远不会停止。pControl->Run()的HRESULT为S_FALSE,这意味着并非所有筛选器都在运行。我不知道为什么会发生这种情况,我觉得在构建这些过滤器时出了问题。
下面是我的资料来源。我已经创建了一个类来处理网络摄像头捕获。在使用中,基本上有两种东西被称为:
webcamCapture::buildFilterGraph()
webcamCapture::runFilter()
runFilter将运行过滤器并将帧保存为位图文件。我是导演的新手,我很确定我错过了一些简单的东西。任何见解都将不胜感激!
源
HRESULT webcamCapture::buildFilterGraph(void){
HRESULT hr;
if (FAILED(hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) {
return hr;
}
createCOMInstances();
// Use findWebCam() to find the webcam and add it to our capture graph
hr = findWebCam();
if(FAILED(hr)){
return hr;
}
// Add the sample grabber to the graph
hr = pGraph->AddFilter(pGrabberF, L"Sample Grabber");
if(FAILED(hr)){
return hr;
}
hr = pGrabberF->QueryInterface(IID_PPV_ARGS(&pGrabber));
if(FAILED(hr)){
return hr;
}
// Set media type for the sample grabber (24-bit RGB Uncompressed video)
ZeroMemory(&mt, sizeof(mt));
mt.majortype = MEDIATYPE_Video;
mt.subtype = MEDIASUBTYPE_RGB24;
hr = pGrabber->SetMediaType(&mt);
if(FAILED(hr)){
return hr;
}
hr = pGraph->AddFilter(pNullF, L"Null Filter");
if(FAILED(hr)){
return hr;
}
// Connect source (pCapF), sample grabber (pGrabberF) and null renderer (pNullF)
pGraphBuilder->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, pCapF,pGrabberF, pNullF);
hr = pGrabber->SetOneShot(TRUE);
hr = pGrabber->SetBufferSamples(TRUE);
return S_OK;
}
HRESULT webcamCapture::runFilter(){
HRESULT hr;
FILTER_STATE filterState;
pBuffer = NULL;
hr = pControl->Run();
if(FAILED(hr)){
goto done;
}
pControl->GetState(1000, (OAFilterState*)&filterState);
long evCode;
hr = pEvent->WaitForCompletion(2000, &evCode);
if(FAILED(hr)){
goto done;
}
long cbBuffer;
hr = pGrabber->GetCurrentBuffer(&cbBuffer, NULL);
if(FAILED(hr)){
goto done;
}
pBuffer = (BYTE*)CoTaskMemAlloc(cbBuffer);
if(!pBuffer){
hr = E_OUTOFMEMORY;
goto done;
}
hr = pGrabber->GetCurrentBuffer(&cbBuffer, (long*)pBuffer);
if(FAILED(hr)){
goto done;
}
hr = pGrabber->GetConnectedMediaType(&mt);
if(FAILED(hr)){
goto done;
}
if((mt.formattype == FORMAT_VideoInfo) && (mt.cbFormat >= sizeof(VIDEOINFOHEADER)) && (mt.pbFormat != NULL)){
VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)mt.pbFormat;
writeBitmap(L"test_image.bmp", &pVih->bmiHeader, mt.cbFormat - SIZE_PREHEADER, pBuffer, cbBuffer);
}
//FreeMediaType(mt);
done:
CoTaskMemFree(pBuffer);
pNullF->Release();
pNullF = NULL;
pCapF->Release();
pCapF = NULL;
pGrabber->Release();
pGrabber = NULL;
pGrabberF->Release();
pGrabberF = NULL;
pControl->Release();
pControl = NULL;
pEvent->Release();
pEvent = NULL;
pGraph->Release();
pGraph = NULL;
CoUninitialize();
return hr;
}
HRESULT webcamCapture::createCOMInstances(void){
HRESULT hr;
// Instructions to create a Capture Graph using CaptureGraphBuilder2 can be found at https://msdn.microsoft.com/en-us/library/windows/desktop/dd373396(v=vs.85).aspx
// Create Capture Graph Builder
hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pGraphBuilder));
if(FAILED(hr)){
return hr;
}
// Create Graph Manager
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pGraph));
if(FAILED(hr)){
return hr;
}
// Initialize Capture Graph Builder by referencing pGraph (Graph Manager)
hr = pGraphBuilder->SetFiltergraph(pGraph);
if(FAILED(hr)){
pGraphBuilder->Release();
return hr;
}
// Set pointer to Media Control Interface
hr = pGraph->QueryInterface(IID_PPV_ARGS(&pControl));
if(FAILED(hr)){
return hr;
}
// Set pointer to Media Event Interface
hr = pGraph->QueryInterface(IID_PPV_ARGS(&pEvent));
if(FAILED(hr)){
return hr;
}
// Create Sample Grabber
// NOTE: ISampleGrabber is depreciated and may not be supported in later versions of Windows!
hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pGrabberF));
if(FAILED(hr)){
return hr;
}
// Create the null renderer filter. We don't be previewing the camera feed so we can just drop the frames when we've converted them to bitmaps
hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pNullF));
if(FAILED(hr)){
return hr;
}
TRACE(_T("Interface Creation Successfuln"));
return S_OK;
}
// Function to find the MS HD3000 webcam (VID=0x045E PID=0x0779)
// For more info on finding devices for Video/Audio capture, see https://msdn.microsoft.com/en-us/library/windows/desktop/dd377566(v=vs.85).aspx
HRESULT webcamCapture::findWebCam(void){
HRESULT hr;
ICreateDevEnum *pDevEnum;
IEnumMoniker *pEnum;
IMoniker *pMoniker;
BOOL isDeviceFound = FALSE;
WORD wNumCameras = 0;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));
if(FAILED(hr)){
return hr;
}
hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, 0);
if(hr == S_FALSE){
return VFW_E_NOT_FOUND;
}
pDevEnum->Release();
// Go through each device moniker and read their Device Path properties. This is how we will find our webcam of interest
while(pEnum->Next(1, &pMoniker, NULL) == S_OK){
IPropertyBag *pPropBag;
VARIANT var;
hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
if(FAILED(hr)){
pMoniker->Release();
continue;
}
VariantInit(&var);
hr = pPropBag->Read(L"DevicePath", &var, 0);
if(SUCCEEDED(hr)){
// String search variables
CString csVidToCompare = _T("");
CString csPidToCompare = _T("");
WORD wVidSearchIndex = 0;
WORD wPidSearchIndex = 0;
CString csDevPath = var.bstrVal;
csDevPath.MakeLower();
wVidSearchIndex = csDevPath.Find(_T("vid_"), 0);
wPidSearchIndex = csDevPath.Find(_T("pid_"), 0);
csVidToCompare = csDevPath.Mid(wVidSearchIndex + 4, 4);
csPidToCompare = csDevPath.Mid(wPidSearchIndex + 4, 4);
// If MS Device is found
if(!csVidToCompare.Compare(_T("045e"))){
// If the 3000HD camera is found
if((!csPidToCompare.Compare(_T("0779"))) && (wNumCameras == 0)){
wNumCameras++;
hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCapF);
if(FAILED(hr)){
return hr;
}
isDeviceFound = TRUE;
// Add the webcam to the filter graph
hr = pGraph->AddFilter(pCapF, L"Capture Filter");
if(FAILED(hr)){
TRACE(_T("Failed to add webcam to filter graphn"));
return hr;
}
TRACE(_T("Webcam found and added to filter!n"));
}
else if((!csPidToCompare.Compare(_T("0779"))) && (wNumCameras > 0)){
TRACE(_T("More than one HD3000 camera found!n"));
continue;
}
else{
TRACE(_T("MS Device found, but not the cameran"));
continue;
}
}
}
pPropBag->Release();
pMoniker->Release();
}
if(isDeviceFound == FALSE){
TRACE(_T("Webcam was not foundn"));
pEnum->Release();
return E_FAIL;
}
pEnum->Release();
return S_OK;
}
代码是正确的。是的,您可以构建这样的图形,并且在一次拍摄模式下的采样采集器接受视频帧并指示完成。
潜在问题清单包括:
- 您的视频设备无法传送帧,采样采集器将永远等待
- 你请求转换为24位RGB,而你的相机更有可能支持其他视频格式,所以你可能会插入另一个转换器过滤器-视频帧可能会离开相机过滤器,并在转换器中丢失;您有兴趣查看您构建的有效图
- 你构建的图表不正确,你的样本抓取器实际上连接不正确
在任何情况下,您要做的第一件事都只是闯入调试器并检查线程,您可能会当场看到错误。然后你要做的第二件事是找出如何查看你的过滤图。这对于任何DirectShow开发都是必须的。
S_FALSE
返回对于拓扑中具有活动源的图是典型的。这很好。
- 警告处理为错误这里有什么问题
- 最小硬币更换问题(自上而下方法)
- 为"adjacent"变量赋值时出现问题
- 我的神经网络不起作用 [XOR 问题]
- 在Ubuntu 16.04上安装Cilk时出现问题
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 编译包含字符串的代码时遇到问题
- Project Euler问题4的错误解决方案
- 问题:什么是QAbstractItemView::NoEditTriggers的反面
- 在编译C++代码(具有dlib和opencv)到WASM时面临问题
- 在进程中对同一管道进行读取和写入时C++管道出现问题
- 静态数据成员的问题-修复链接错误会导致编译器错误
- C++ 雷神库 - 使用资源加载器类时出现问题(不命名类型)
- 一个关于在C++中重载布尔运算符的问题
- 首要问题的答案让值班员搞错了
- setlocale的C++土耳其字符串问题
- 如何重构类层次结构以避免菱形问题
- 基于boost的程序的静态链接——zlib问题
- C++格式化输出问题
- 在CaptureGraphBuilder2中使用SampleGrabber时出现的问题