Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

2 USB cameras using Direct Show

263 views
Skip to first unread message

Jonathan Arnold

unread,
Aug 18, 2003, 9:59:13 PM8/18/03
to
I want to be able to run two (or more) instances of my program,
each of which shows a preview of a connected USB camera. I'm
pretty close to doing that successfully, but I've run into a
small problem.

My setup:
- Win2k
- DirectX 9
- 2 USB video cameras (IBM PC Net Camera & Sony Handycam)

Using the AMCAP sample app from the SDK, this works fine. I can
run two copies of AMCAP and select and run either one (of course,
they can't both be previewing the same camera). However, both
my app and the PLAYCAP sample app have the same problem. I've
modified the PLAYCAP sample so it will loop on the available
cameras and run the n'th camera based upon the number you pass
on the command line (so a '0' will run camera #1, while a '1'
will run the second camera it finds). If I run either app and
am previewing camera #1 (the PC Net Camera), when I run the
app the second time, trying to concurrently display camera
#2, I get an error return from the call to RenderStream. The
error is 0x80070057, which is, according to the error lookup,
an incorrect parameter.

If I do it the other way (ie., preview camera #2 and then
camera #1), everything works just fine - I get both cameras
happily previewing. It's ony if I start by previewing camera
#1. And, again, AMCAP works just fine, no matter which one
I'm viewing.

I've tried changing PLAYCAP to mimic more how AMCAP sets up and
runs the graph, to no luck.

Any hints on what I should try next? I'm thinking that something
isn't getting released, maybe in the enum part. Here's the code
in PLAYCAP that I added:

hr = pDevEnum->CreateClassEnumerator (CLSID_VideoInputDeviceCategory, &pClassEnum, 0);

if ( camera != 0 )
pClassEnum->Skip( camera );

if (S_OK == (pClassEnum->Next (1, &pMoniker, &cFetched)))

So basically I merely add the call to the Skip. I've also just tried
enumerating through the camers, but that doesn't help either.

--
Jonathan Arnold (mailto:jdar...@buddydog.org)
The Incredible Brightness of Seeing, a Home Theater weblog
http://www.anaze.us/HomeTheater

Paulius Zaleckas (Studija X)

unread,
Aug 19, 2003, 4:22:44 AM8/19/03
to
pClassEnum->Reset();
before skiping and enumerating next should solve everything.

"Jonathan Arnold" <jdarnold_online@insors_comm.com> wrote in message
news:etCdnalSU4D...@speakeasy.net...

Jonathan Arnold

unread,
Aug 19, 2003, 10:19:41 AM8/19/03
to
Paulius Zaleckas (Studija X) wrote:
> "Jonathan Arnold" <jdarnold_online@insors_comm.com> wrote in message
> news:etCdnalSU4D...@speakeasy.net...
>>Any hints on what I should try next? I'm thinking that something
>>isn't getting released, maybe in the enum part. Here's the code
>>in PLAYCAP that I added:
>>
>> hr = pDevEnum->CreateClassEnumerator (CLSID_VideoInputDeviceCategory,
>
> &pClassEnum, 0);
>
>> if ( camera != 0 )
>> pClassEnum->Skip( camera );
>>
>> if (S_OK == (pClassEnum->Next (1, &pMoniker, &cFetched)))
>>
>>So basically I merely add the call to the Skip. I've also just tried
>>enumerating through the camers, but that doesn't help either.
> pClassEnum->Reset();
> before skiping and enumerating next should solve everything.

Ahh, no fair - you got my hopes all up. Unfortunately, that didn't
help. It is certainly a Good Idea(tm), so I'll keep it, but it still
gives me the same error.

The March Hare (MVP)

unread,
Aug 19, 2003, 6:35:21 PM8/19/03
to

Jonathan Arnold

unread,
Aug 21, 2003, 1:57:48 PM8/21/03
to

Doesn't really help. I looked at all of these postings, and they
don't quite talk about what I'm trying to do, although I find it
hard to believe it can be that rare. Besides, most of these postings
are a year or more old at this point, as they talk about upgrading
to 8.1 as a solution.

I'm not even trying to be tricky and capturing two or more previews
at the same time in the same program. I'm just trying to run my
program twice and capture different devices. They don't even have to
be USB cameras. I have 3 machines with multiple WDM video capture
devices, and they all fail in the same way. One machine has 2 USB
cameras, 1 machine has a 4 video input card, and another machine has
a video input card and a USB camera. They all fail if you are previewing
the "first" device and try to preview the "second" one. If you do it
the other way around, it works fine. And AMCAP seems to work in any case.

Here is the guts of the PLAYCAP sample that I've modified. All error
checking has been removed, but otherwise it is verbatim. The global
cameraIndex is set, the window is created and then VideoCapture is
called. You could even call it a skeleton preview application.

int cameraIndex=0; // Which camera to use
IVideoWindow * g_pVW = NULL;
IMediaControl * g_pMC = NULL;
IMediaEventEx * g_pME = NULL;
IGraphBuilder * g_pGraph = NULL;
ICaptureGraphBuilder2 * g_pCapture = NULL;
IAMVideoCompression* g_pVC=NULL;
IBaseFilter *pSrcFilter=NULL;

HRESULT FindCaptureDevice()
{
HRESULT hr;
IBaseFilter * pSrc = NULL;
CComPtr <IMoniker> pMoniker =NULL;
ULONG cFetched;

// Create the system device enumerator
CComPtr <ICreateDevEnum> pDevEnum =NULL;
hr = CoCreateInstance (CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
IID_ICreateDevEnum, (void ** ) &pDevEnum);

// Create an enumerator for the video capture devices
CComPtr <IEnumMoniker> pClassEnum = NULL;


hr = pDevEnum->CreateClassEnumerator (CLSID_VideoInputDeviceCategory, &pClassEnum, 0);

pClassEnum->Reset();

if ( cameraIndex > 0 )
pClassEnum->Skip( cameraIndex );

if (S_OK == (pClassEnum->Next (1, &pMoniker, &cFetched)))

{
IPropertyBag *pBag;
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);
if(SUCCEEDED(hr)) {
USES_CONVERSION;
VARIANT var;
var.vt = VT_BSTR;
hr = pBag->Read(L"FriendlyName", &var, NULL);
if(hr == NOERROR) {
WCHAR wachFriendlyName[111];
lstrcpyW(wachFriendlyName, var.bstrVal);
SysFreeString(var.bstrVal);
SetWindowText( ghApp, W2T(wachFriendlyName) );
}
pBag->Release();
}

// Bind Moniker to a filter object
hr = pMoniker->BindToObject(0,0,IID_IBaseFilter, (void**)&pSrc);
}

return hr;
}


HRESULT CaptureVideo()
{
HRESULT hr;

// Get DirectShow interfaces
// Create the capture graph builder
hr = CoCreateInstance (CLSID_CaptureGraphBuilder2 , NULL, CLSCTX_INPROC,
IID_ICaptureGraphBuilder2, (void **) &g_pCapture);

// Use the system device enumerator and class enumerator to find
// a video capture/preview device, such as a desktop USB video camera.
hr = FindCaptureDevice();

// Create the filter graph
hr = CoCreateInstance (CLSID_FilterGraph, NULL, CLSCTX_INPROC,
IID_IGraphBuilder, (void **) &g_pGraph);

// Attach the filter graph to the capture graph
hr = g_pCapture->SetFiltergraph(g_pGraph);

// Add Capture filter to our graph.
hr = g_pGraph->AddFilter(pSrcFilter, L"Video Capture");

hr = g_pCapture->FindInterface(&PIN_CATEGORY_CAPTURE,
&MEDIATYPE_Video,
pSrcFilter, IID_IAMVideoCompression,
(void **)&g_pVC);

// Render the preview pin on the video capture filter
// Use this instead of g_pGraph->RenderFile
hr = g_pCapture->RenderStream (&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,
pSrcFilter, NULL, NULL);

hr = g_pGraph->QueryInterface(IID_IVideoWindow, (LPVOID *) &g_pVW);

hr = g_pGraph->QueryInterface(IID_IMediaEventEx, (LPVOID *) &g_pME);

// Set the window handle used to process graph events
hr = g_pME->SetNotifyWindow((OAHWND)ghApp, WM_GRAPHNOTIFY, 0);

// Obtain interfaces for media control and Video Window
hr = g_pGraph->QueryInterface(IID_IMediaControl,(LPVOID *) &g_pMC);

// Set video window style and position
// Set the video window to be a child of the main window
hr = g_pVW->put_Owner((OAHWND)ghApp);

// Set video window style
hr = g_pVW->put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN);

// Make the video window visible, now that it is properly positioned
hr = g_pVW->put_Visible(OATRUE);

// Start previewing video data
hr = g_pMC->Run();

return S_OK;
}


--
Jonathan Arnold (mailto:jdarnold_online@insors_comm.com)
Amazing Developments http://www.buddydog.org

Jonathan Arnold

unread,
Aug 26, 2003, 11:05:24 AM8/26/03
to
> Doesn't really help. I looked at all of these postings, and they
> don't quite talk about what I'm trying to do, although I find it
> hard to believe it can be that rare. Besides, most of these postings
> are a year or more old at this point, as they talk about upgrading
> to 8.1 as a solution.

Just thought I'd add that, via one of my free support issues I
get from MSDN, I was able to nearly resolve my problem, thanks to
Sameer's help. I solved the problem with 2 USB cameras and it
boiled down to something very simple (of course!) - Bandwidth.
Depending on the size of the preview window, 1 USB camera can
max out the bandwidth, so when you turn on the second one, it
will return an error that means it didn't have the bandwidth.

This can be fixed by either using a smaller, less intensive
preview window or by moving the camera to the "other" USB
device, as most computers come with 4 USB ports on 2 USB
devices.

You can check this by looking at the bandwidth meter found on
the Advanced tab of the USB device Properties dialog, something
I never knew about. Run one camera and you can see the bandwidth
spike to over 70%, leaving not a lot of room for the second
camera.

I still have a problem with two cameras, one a USB and the other
the video in port on my nVidia card, but even AMCAP acts oddly at
times with this setup. It is probably some other bottleneck
somewhere, and I still hope to track it down.

--
Jonathan Arnold C/C++/CBuilder Keen Advice:
http://www.keen.com/categories/categorylist_expand.asp?sid=5156620
Comprehensive C++Builder link site:
http://www.buddydog.org/C++Builder/c++builder.html

0 new messages