如何选择视频采集设备? [英] How to choose a video capture device?

查看:99
本文介绍了如何选择视频采集设备?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

你好!

我正在使用3个网络摄像头进行编程,以构建预览视频,然后分别拍摄3张照片.我的开发环境是Visual Studio C ++ 2010 Express/CLR/Windows Forms应用程序.

我已经可以在我的电脑上成功获得三个预览视频.但是我面临一个大问题:当我使用相同的代码将网络摄像头连接到另一台计算机时,捕获会出现错误(程序中断或以不同顺序显示视频).

在多台计算机上测试完之后,
我终于找到了原因.当网络摄像头连接到另一台PC时,当新PC对设备进行计数时,新PC可能会获得新的顺序(这意味着它们在我的PC上作为USB设备1、2、3;它们在新电脑作为USB设备2、1、3).但是我需要像以前一样使用网络摄像头. pictureBox1上的webcam1,pBox2上的webcam2和pBox3上的webcam3.而且我希望我的代码在所有PC和任何网络摄像头上都普遍有用.

这也意味着我想在窗口(3个PictureBoxes)上以用户所需"的顺序选择网络摄像头.现在,我正在考虑解决此问题的一种方法,即在每个pictureBox下方放置一个comboBox,该组合框用于为每个pictureBox选择设备.但是我不知道该如何实现.请你帮助我好吗?还是您有更好的主意来防止问题发生???

还有什么可能非常重要:CamShow.cpp中的计数设备方法是否可能出错?我应该在那里做些校正器吗?

任何答案将不胜感激!

我最近的代码是:

Form.h:

Hello!

I''m programing with 3 webcams to build preview videos and then take 3 pictures from each one. My developing environment is visual studio c++ 2010 express/ clr/ windows forms app.

I can already successfully get three preview videos on my pc. But I''m facing with a big problem: when I connect my webcams to another computer using the same code, the capturing has an error (program breaks or showing videos in a different order).

After I tested this on several computers,
I finally found the reason. It is when the webcams are connected to another pc, the new pc may get a new order of them when the new pc counts the devices (Which means they were on my pc as usb-device 1, 2, 3; they are on the new pc as usb-device 2, 1, 3). But I need to use the webcams in the order like before. Webcam1 on pictureBox1, webcam2 on pBox2, and webcam3 on pBox3. And I would like my code to be generally useful, whatever on which pc and with any webcams.

What also means, I want to choose the webcams in an "user-wanted" order on the window(of 3 pictureBoxes). Now I''m thinking of one way to solve this, namely to put a comboBox under each pictureBox, which are used to choose the device for each pictureBox. But I don''t know how to realize that. Could you please help me? Or do you have a better idea to prevent the problem???

What may also be very important: Could it be wrong with my counting devices method in the CamShow.cpp? Should I make some correctors there?

Any answers would be appreciated!

My recently code is:

Form.h:

private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
	CamShow test1;
        CamShow test2;
        CamShow test3;

	button1->Enabled=false; 
        
        hr = test1.InitComLib();
	hr = test1.CaptureVideo(1);
	System::Drawing::Rectangle rc = pictureBox1->ClientRectangle;
	hr = test1.pVW->put_Owner(OAHWND(this->pictureBox1->Handle.ToInt64()));

hr = test1.pVW->put_WindowStyle( WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN );
hr = test1.pVW->SetWindowPosition( 0, 0, rc.Right, rc.Bottom );
hr = test1.pMC->Run();

        test1.ControlRelease();
	test1.EventRelease();
	test1.GraphBuilderRelease();
        test1.CoUnini();

        hr = test2.InitComLib();
        hr = test2.CaptureVideo(2);
	System::Drawing::Rectangle rc = pictureBox1->ClientRectangle;
	hr = test2.pVW->put_Owner(OAHWND(this->pictureBox1->Handle.ToInt64()));
        // IVideoWindow *pVW

hr = test2.pVW->put_WindowStyle( WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN );
hr = test2.pVW->SetWindowPosition( 0, 0, rc.Right, rc.Bottom );
hr = test2.pMC->Run();

        test2.ControlRelease();
	test2.EventRelease();
	test2.GraphBuilderRelease();
        test2.CoUnini();

        hr = test3.InitComLib();
        hr= test3.CaptureVideo(3);
	System::Drawing::Rectangle rc = pictureBox1->ClientRectangle;
	hr = test3.pVW->put_Owner(OAHWND(this->pictureBox1->Handle.ToInt64()));

hr = test3.pVW->put_WindowStyle( WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN );
hr = test3.pVW->SetWindowPosition( 0, 0, rc.Right, rc.Bottom );
hr = test3.pMC->Run();

        test3.ControlRelease();
	test3.EventRelease();
	test3.GraphBuilderRelease();
        test3.CoUnini();
}



CamShow.cpp:

我在这里给出了最相关的代码段来解决我的问题.而且变量函数的声明在CamShow.h中,我想我不需要在这里复制;).



CamShow.cpp:

I give the most relevant code-sections to my problem here. And the declarations of variables functions are in CamShow.h, which I don''t need to copy here for you I think ;).

#include "stdafx.h"
#include <DShow.h>
#include <Windows.h>
#include <comdef.h>
#include "CamShow.h"

CamShow::CamShow() {...}
CamShow::~CamShow() {}

HRESULT CamShow::InitComLib()
	{
		HRESULT hr = NULL;
		hr = CoInitialize(NULL);
		return hr;
	}
HRESULT CamShow::CaptureVideo(int NO)
	{
		HRESULT hr;
		IBaseFilter *pSrcFilter=NULL;

		// Get DirectShow interfaces
		hr = GetInterfaces();
		if (FAILED(hr))
		{
			Msg(TEXT("error get interfaces: hr=0x%x"), hr);
			return hr;
		}

                // Attach the filter graph to the capture graph
		hr = pCGB2->SetFiltergraph(pGraphBuilder); //pCGB2: ICaptureGraphBuilder2 *pCGB2 = NULL;
		if (FAILED(hr))
		{
			Msg(TEXT("error Set Filtergraph: hr=0x%x"), hr);
			return hr;
		}

                // Use the system device enumerator and class enumerator to find
             // a video capture/preview device, such as a desktop USB video camera.
		hr = FindCaptureDevice(&pSrcFilter, NO); 
		if (FAILED(hr))
		{
               // Don''t display a message because FindCaptureDevice will handle it
			return hr;
		}

                // Add Capture filter to our graph. 
		hr = pGraphBuilder->AddFilter(pSrcFilter, L"Capture Filter");
		if (FAILED(hr))
		{
			Msg(TEXT("Couldn''t add the capture filter to the graph!  hr=0x%x\r\n\r\n") 
            TEXT("If you have a working video capture device, please make sure\r\n")
            TEXT("that it is connected and is not being used by another application.\r\n\r\n")
            TEXT("The sample will now close."), hr);
                        pSrcFilter->Release();
			return hr;
		}

		// Render the preview pin on the video capture filter
                hr = pCGB2->RenderStream (&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,				          pSrcFilter, NULL, NULL);
		if (FAILED(hr))
		{
			Msg(TEXT("Couldn''t render the video capture stream.  hr=0x%x\r\n"), hr);
			pSrcFilter->Release();
			return hr;
		}

// Now that the filter has been added to the graph and we have
// rendered its stream, we can release this reference to the filter.	
pSrcFilter->Release();
		

		// Set video window style and position		
                hr = intSetupVideoWindow();
		if (FAILED(hr))
		{
			Msg(TEXT"Couldn''t initialize video window!  hr=0x%x"),hr);
			return hr;
		}

		// Start previewing video data
                hr = pMC->Run();  // IMediaControl *pMC
                if (FAILED(hr))
                {
                  Msg(TEXT("Couldn''t run the graph!  hr=0x%x"), hr);
                  return hr;
                }

                // Remember current state
                psCurrent = Running;
        
                return S_OK;	
}

HRESULT CamShow::FindCaptureDevice(IBaseFilter ** ppSrcFilter, int NO)
	{
		HRESULT hr = S_OK;
		IBaseFilter * pSrc = NULL;
		IMoniker* pMoniker = NULL;
		ULONG cFetched;
		int DevNo=0;

		IEnumMoniker *pClassEnum = NULL;
		ICreateDevEnum *pDevEnum =NULL;

		if (!ppSrcFilter)  return E_POINTER; 		
		
                // Create the system device enumerator
		hr = CoCreateInstance (CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
					IID_ICreateDevEnum, (void **) &pDevEnum);
		if (FAILED(hr))
		{
		Msg(TEXT("Couldn''t create system enumerator!  hr=0x%x"), hr);		        }
	
		 // Create an enumerator for the video capture devices
		if (SUCCEEDED(hr))
		{
              hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pClassEnum, 0);
			if (FAILED(hr))
			{
		        Msg(TEXT("Couldn''t create class enumerator!  hr=0x%x"), hr);			}
			pDevEnum->Release();
		}

		if (SUCCEEDED(hr))
		{
		// If there are no enumerators for the requested type, then 
		// CreateClassEnumerator will succeed, but pClassEnum will be NULL.			if (pClassEnum == NULL)
			{
				MessageBox(ghApp,TEXT("No video capture device was detected.\r\n\r\n")
				TEXT("This sample requires a video capture device, such as a USB WebCam,\r\n")
				TEXT("to be installed and working properly.  The sample will now close."),
				TEXT("No Video Capture Hardware"), MB_OK | MB_ICONINFORMATION);				
                         hr = E_FAIL;
			}
		}


// This section counts the webcam devices on the computer!! 
		while (pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK)
		{	
			IPropertyBag *pBag = NULL;
                        BSTR sName;
			VARIANT var;
			VariantInit(&var);
	hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);

			 hr = pBag->Read(L"FriendlyName", &var, 0); 
			 sName = var.bstrVal; // Get the name, but not to be used
			 // Count the devices and give them the number in the order:1, 2, 3, ...
                         DevNo++;
			 VariantClear(&var);

			 if (SUCCEEDED(hr))
			 {
				 if (DevNo==NO) // I think this condition is problematic and kritic. What I thought is to get webcam N on pictureBox N, because I thought the devices should be counted in a same order on different PCs, that''s wrong acturally.
		           { 
              // Bind Moniker to a filter object for every webcam 
	      hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void **)&pSrc);
	      if (FAILED(hr))
              return hr;
              
              pBag->Release();                 
	      pMoniker->Release();                 
              break; 
			   }
			 }

		}

        // Copy the found filter pointer to the output parameter.     
        if (SUCCEEDED(hr))
        {
	  *ppSrcFilter = pSrc;
	  (*ppSrcFilter)->AddRef();
	}


	return hr;
       }

......(Other functions)




我希望我已经清楚地解释了我的问题.如果您不清楚什么,请告诉我,我将回答您并改善我的问题.

感谢您的帮助!




I hope I''ve explained my problem clearly. If anything is not clear for you, just tell me and I''m going to answer you and improve my question.

Thanks for helping!

推荐答案

您好,

设备会按照最初出现在系统中的顺序进行枚举(已安装/USB已连接等).要识别摄像机,可以使用绰号显示名称.是包含系统中设备的完整路径,它可以包含设备PID和VID或其他设备密钥,此外,您还可以访问实际的驱动程序-因此,无论如何您都可以尝试标识设备并建立正确的顺序.连同它,您可以使用摄像机名称对其进行排序.

1.获取昵称显示名称:
Hello,

Devices are enumerated in your PC according they were initially appear in the system (Installed/USB Connected and so on). To identify the camera you can use moniker display name. Is contains full path to the device in a system, It can contains device PID and VID or other device key, plus you can get access to the actual driver - so you can try to idendify devices anyway you need and build the proper order. Along with it you can sort this with names of cameras.

1. Get''s moniker display name:
HRESULT hr;
CComPtr< IMoniker > pMoniker;
// initialized moniker
CComPtr<IBindCtx> pBindCtx = NULL;
hr = CreateBindCtx(NULL,&pBindCtx);
if (SUCCEEDED(hr))
{
    LPOLESTR  lpszDisplayName   = NULL;
    hr = pMoniker->GetDisplayName(pBindCtx,NULL,&lpszDisplayName);
    if (lpszDisplayName)
    {
        // Use display name
        // ....
        // Clear memory
        CComPtr<IMalloc> pMalloc;
        hr = CoGetMalloc(1,&pMalloc);
        if (SUCCEEDED(hr)) pMalloc->Free(lpszDisplayName);
    }
}


2.从名字显示名称创建IBaseFilter:


2. Create IBaseFilter from moniker display name:

HRESULT hr;
LPCWSTR szMoniker = L""; // your moniker display name
CComPtr<IBaseFilter> pFilter;
CComPtr<IBindCtx> pBindCtx;
hr = CreateBindCtx(0, &pBindCtx);
ULONG chEaten = 0;
CComPtr<IMoniker> pMoniker;
hr = MkParseDisplayName(pBindCtx, szMoniker, &chEaten, &pMoniker); // Create Moniker from display name
if (SUCCEEDED(hr))
{
    // Bind moniker to a DirectShow filter.
    hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pFilter);
    if (SUCCEEDED(hr))
    {
        // Usage of pFilter
    }
}


3.如何获取相机名称:


3. How to get camera name:

HRESULT hr;
CComPtr< IMoniker > pMoniker; // initialized before

CComPtr< IPropertyBag > pBag;
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**) &pBag);
if(SUCCEEDED(hr))
{
    VARIANT var;
    VariantInit(&var);
    hr = pBag->Read(L"FriendlyName",&var, NULL);
    if(SUCCEEDED(hr))
    {
        // Usage of device name - var.bstrVal
        wprintf(L"%s",var.bstrVal); // - Just an example of usage
    }
    VariantClear(&var);
}


我认为您不需要直接访问驱动程序对象,而是可以通过IKsObject接口和KsSynchronousDeviceControl API来访问.
附加说明-您应该查看代码(我只是看FindCaptureDevice函数),其中包含大量内存泄漏-您无法处理释放COM对象的情况,如果HRESULT失败,则会导致应用程序崩溃.
其他每个线程仅调用一次的CoInitialize必需;如果您在一个线程中初始化并使用相机,则不需要在初始化之前每次都调用它.
我建议您阅读有关COM的信息以及如何使用它.

问候,
Maxim.


I think you not be require to access driver object directly but that possible via IKsObject interface and KsSynchronousDeviceControl API.
Additional notes - you should review your code (I just look at the FindCaptureDevice function) it consist of a lot of memory leaks - you are not handle releasing COM objects, in case of HRESULT failure you will get app crash.
Other CoInitialize necessary to call only one time for each thread; if you initialize and use your cameras in one thread you are not require to call it each time before initialization.
I suggest you to read information about COM, and how to use it.

Regards,
Maxim.


这篇关于如何选择视频采集设备?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆