Click here to Skip to main content
15,892,643 members

How to choose a video capture device?

christmars asked:

Open original thread
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:

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!
Tags: C#, C++/CLI, Windows Forms, DirectShow

Plain Text
ASM
ASP
ASP.NET
BASIC
BAT
C#
C++
COBOL
CoffeeScript
CSS
Dart
dbase
F#
FORTRAN
HTML
Java
Javascript
Kotlin
Lua
MIDL
MSIL
ObjectiveC
Pascal
PERL
PHP
PowerShell
Python
Razor
Ruby
Scala
Shell
SLN
SQL
Swift
T4
Terminal
TypeScript
VB
VBScript
XML
YAML

Preview



When answering a question please:
  1. Read the question carefully.
  2. Understand that English isn't everyone's first language so be lenient of bad spelling and grammar.
  3. If a question is poorly phrased then either ask for clarification, ignore it, or edit the question and fix the problem. Insults are not welcome.
  4. Don't tell someone to read the manual. Chances are they have and don't get it. Provide an answer or move on to the next question.
Let's work to help developers, not make them feel stupid.
Please note that all posts will be submitted under the http://www.codeproject.com/info/cpol10.aspx.



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900