AddSourceFilterForMoniker() locks up sometimes.

From: Brian Stone (no.more.spam_at_stoneentertainment.com)
Date: 06/19/04


Date: 18 Jun 2004 20:20:07 -0700

I've coded a simple filter graph to capture frames from a video camera
via the Sample Grabber filter. To find the camera, I build the
enumated list of devices and pick the first one out of the list,
exactly as in Microsoft's source examples. I then add the camera
filter to the graph via AddSourceFilterForMoniker. However, sometimes
this function will lock up... like it's in a deadlock situtation or an
infinite loop. It simply stops and never returns.

My application works great when AddSourceFilterForMoniker returns
succesfully! I can grab frames from the Sample Grabber with no
problems at all. However, about half the time,
AddSourceFilterForMoniker just stops for no apparent reason, and the
program has to be restarted.

When I quit the program, I make sure to properly release all of the
filter interfaces and call CoUninitialize() in the same thread that
initialized the COM. I also check all errors from every function, and
everything appears to be S_OK. So... any ideas?

I've posted the relevent code below. This isn't the whole program,
but this is the exact series of code that is executed, starting at the
initialization of the COM up to the AddSourceFilterForMoniker()
function.

A lot of this is Microsoft's own sample code from the MSDN website.

Thanks for any help!

Sincerely,
  Brian Stone

HWND ghApp;
DWORD g_dwGraphRegister = 0;
IMediaControl *g_pMC = NULL;
IMediaEventEx *g_pME = NULL;
IFilterGraph2 *g_pGraph = NULL;
ICaptureGraphBuilder2 *g_pCapture = NULL;
IBaseFilter *g_pGrabberFilter = NULL;
IBaseFilter *g_pNullFilter = NULL;
ISampleGrabber *g_pGrabberInterface = NULL;

// Initialize COM
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if(FAILED(hr))
{
    Msg(TEXT("CoInitialize Failed!\r\n"));
    return 0;
}

// ------------------------
// To capture video we have to build a DirectShow filter graph.
// The first step is to create a filter graph object.
        
// Create the filter graph object.
hr = CoCreateInstance (CLSID_FilterGraph, NULL, CLSCTX_INPROC,
IID_IFilterGraph2, (void **) &g_pGraph);
if (FAILED(hr))
    return hr;

// ------------------------
// Next, we'll create a capture graph builder.

hr = CoCreateInstance (CLSID_CaptureGraphBuilder2 , NULL,
CLSCTX_INPROC, IID_ICaptureGraphBuilder2, (void **) &g_pCapture);
if (FAILED(hr))
    return hr;

// ------------------------
// Create the filters that we will add to our filter graph.
        
// Create a sample grabber filter.
hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (void**)&g_pGrabberFilter);
if (FAILED(hr))
        return hr;
        
// Create a null renderer filter. This filter will be attached to the
output
// pin of the sample grabber.
hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (void**)&g_pNullFilter);
if (FAILED(hr))
        return hr;

// ------------------------
// Next, get the required interfaces.
        
// We need to get the sample grabber filter's interface so we can
configure
// that filter.
hr = g_pGrabberFilter->QueryInterface(IID_ISampleGrabber,
(void**)&g_pGrabberInterface);
if (FAILED(hr))
        return hr;
        
// We also need to get the Media Control interface for the filter
graph. We
// need this to run the graph by calling the Run() method avaliable
only
// through this interface.
hr = g_pGraph->QueryInterface(IID_IMediaControl,(LPVOID *) &g_pMC);
if (FAILED(hr))
    return hr;
        
// We also need to get the Media Event interface for the filter graph.
// This interface has the WaitForCompletion() method.
hr = g_pGraph->QueryInterface(IID_IMediaEvent, (LPVOID *) &g_pME);
if (FAILED(hr))
    return hr;
        
// Set the window handle used to process graph events.
hr = g_pME->SetNotifyWindow((OAHWND)ghApp, WM_GRAPHNOTIFY, 0);
if (FAILED(hr))
        return hr;

// ------------------------
// Now is a good time to configure any filter interfaces we've
requested.
        
// We need to set the "media type" of the sample grabber filter. This
is the
// pixel format of the filter's internal buffer. In this case, we
will
// request uncompressed 24-bit RGB image data.
AM_MEDIA_TYPE mt;
ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
mt.majortype = MEDIATYPE_Video; // Specify uncompressed video data.
mt.subtype = MEDIASUBTYPE_RGB24; // Specify 24-bit RGB pixel format.
hr = g_pGrabberInterface->SetMediaType(&mt);
if (FAILED(hr))
    return hr;
        
// The sample grabber doesn't buffer data, by default. So, we need to
tell it
// to buffer the incoming video frames. The other way to capture
frames would
// be to create a callback function.
hr = g_pGrabberInterface->SetBufferSamples(TRUE);
if (FAILED(hr))
        return hr;
        
// With the sample grabber filter set up as it is right now, we can
grab the
// current frame of video from the sample grabber by calling the
// GetCurrentBuffer method in the sample grabber interface object.
But,
// first, we need to add the filters to the graph and then connect the
filters
// together.
        
// Add the filters to the filter graph. Note... this doesn't create
the graph
// tree itself. It mearly makes the filters avaliable to the graph so
we can
// construct the graph later on.
hr = g_pGraph->AddFilter(g_pGrabberFilter, L"Sample Grabber" );
if (FAILED(hr))
        return hr;
        
hr = g_pGraph->AddFilter(g_pNullFilter, L"Null Renderer" );
if (FAILED(hr))
        return hr;

// ------------------------
// Before we can begin building the capture graph with the capture
graph
// builder object, we need to find a video capture device connected to
the
// computer and get it's "moniker".
        
ULONG cFetched;
IMoniker *pMoniker;
        
// Create a system device enumerator object.
CComPtr <ICreateDevEnum> pDevEnum = NULL;
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);
    return hr;
}
        
// Create an enumerator for the video capture devices.
CComPtr <IEnumMoniker> pClassEnum = NULL;
hr = pDevEnum->CreateClassEnumerator (CLSID_VideoInputDeviceCategory,
&pClassEnum, 0);
if (FAILED(hr))
{
    Msg(TEXT("Couldn't create class enumerator! hr=0x%x"), hr);
    return 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);
    return E_FAIL;
}
        
// Use the first video capture device on the device list.
// Note that if the Next() call succeeds but there are no monikers,
// it will return S_FALSE (which is not a failure). Therefore, we
// check that the return code is S_OK instead of using SUCCEEDED()
macro.
if (S_OK != (pClassEnum->Next (1, &pMoniker, &cFetched)))
{
    Msg(TEXT("Unable to access a video capture device!"));
    return E_FAIL;
}

// --------------
// Finally... we're not done yet... but finally, we can start to build
the
// filter graph. The first object you always have to connect in a
filter
// graph is a video source. In this case, the video source is the
video
// capture device that we just found. We can call the
// AddSourceFilterFromMoniker method in the filter graph object to
// automiatically choose the appropriate source filter for the device
we just
// found and add that filter to the filter graph. Again, this doesn't
connect
// the filter's input or output pins to anything, it just adds the
filter to
// the graph.

USES_CONVERSION;
IBaseFilter *pCaptureDeviceFilter=NULL;
        
// Get the display name of the moniker
LPOLESTR strMonikerName=0;
hr = pMoniker->GetDisplayName(NULL, NULL, &strMonikerName);
if (FAILED(hr))
{
    Msg(TEXT("Couldn't get moniker's display name! hr=0x%x"), hr);
    return hr;
}
        
// Create a bind context needed for working with the moniker
IBindCtx *pContext=0;
hr = CreateBindCtx(0, &pContext);
if (FAILED(hr))
{
    Msg(TEXT("Couldn't create a bind context for moniker! hr=0x%x"),
hr);
    return hr;
}
        

hr = g_pGraph->AddSourceFilterForMoniker(pMoniker, pContext,
strMonikerName, &pCaptureDeviceFilter);
if (FAILED(hr))
{
    Msg(TEXT("Failed in AddSourceFilterForMoniker()! hr=0x%x"), hr);
    return hr;
}

/*****************************************************************
At this point AddSourceFilterForMoniker() will sometimes lock up,
and sometimes it will return properly. It locks up about half the
time. When that happens I have to restart the program and try
again. Sometimes it takes three or four restarts of the application
to get it to work. I don't have a clue why this happens. Any and
all help to solve this problem is greatly appreciated.
******************************************************************/



Relevant Pages

  • Re: Problem: color space conversion by DirectShow
    ... > After that I call series of filters that requiere YUY2 ... AviSynth clearly does not build the same graph otherwise it ... any filter that can extract data from the graph?). ... the video renderer, which won't be the case in AviSynth, the ...
    (microsoft.public.win32.programmer.directx.video)
  • Unable to Stop a graph
    ... I wrote code to programmaticaly build a filter graph to play MPEG-2 ... As MPEG-2 video decoder, I am using the ULead, uldsmpeg.ax filter. ...
    (microsoft.public.win32.programmer.directx.video)
  • AVI mux does not create a valid file, while renderer displays content very good!?
    ... One is connected to video source and last filter is ... source filter which is client for server filter from the first graph. ...
    (microsoft.public.win32.programmer.directx.video)
  • Re: Intelligently Selecting SampleGrabber MediaType
    ... The DivX decoder filter reports only having 1 pin, an input pin, so it ... This now connects into any graph automatically, ... I create the graph automatically without sample grabber, ...
    (microsoft.public.win32.programmer.directx.video)
  • AddSourceFilterForMoniker() locks up sometimes.
    ... I've coded a simple filter graph to capture frames from a video camera ... I can grab frames from the Sample Grabber with no ...
    (microsoft.public.multimedia.directx.dshow.programming)