Sample grabber does not invoke callback function / no live webcam image

Dec 15, 2009 at 2:46 PM
Edited Dec 15, 2009 at 9:38 PM

First, many thanks for providing this great media library for WPF; we highly appreciate your work!

We use the VideoCaptureElement (Changeset 31944) in a WPF application in order to display a webcam live image and grab a sample every now and then. The application runs on several computers (WindowsXP). On most computers, everything works just as expected. Yet, one fails to show a live image, while another shows the live image, but ISampleGrabberCB.SampleCB does not get called. Due to my very limited knowledge on DirectShow, I have no clue how this discrepancy comes about. Anyway I was able to modify the SetupGraph method in the VideoCapturePlayer class in such a way that the sample grabber works. The modified code magically also solves the live image problem on the one computer. Even though I am sure that there is a better and more elegant solution to the mentioned problems, I thought I would share here the solution that worked for me:

Original code:

if (EnableSampleGrabbing)
{
m_sampleGrabber = (ISampleGrabber)new SampleGrabber();
SetupSampleGrabber(m_sampleGrabber);
hr = m_graph.AddFilter(m_sampleGrabber as IBaseFilter, "SampleGrabber");
DsError.ThrowExceptionForHR(hr);
}

var videoOutPin = DsFindPin.ByDirection(m_captureDevice, PinDirection.Output, 0);

if (videoOutPin == null)
throw new Exception("Could not query the video output pin on source filter");

/* Intelligently connect the pins in the graph to the renderer */
hr = m_graph.Render(videoOutPin);

Modified code:

IPin videoOutPin;

if (EnableSampleGrabbing)
{
m_sampleGrabber = (ISampleGrabber)new SampleGrabber();
SetupSampleGrabber(m_sampleGrabber);
hr = m_graph.AddFilter(m_sampleGrabber as IBaseFilter, "SampleGrabber");
DsError.ThrowExceptionForHR(hr);

//Connect capture filter to sample grabber filter
hr = m_graph.Connect(DsFindPin.ByDirection(m_captureDevice, PinDirection.Output, 0),
DsFindPin.ByDirection(m_sampleGrabber as IBaseFilter, PinDirection.Input, 0)
);
DsError.ThrowExceptionForHR(hr);

//Use sample grabber output to render image
videoOutPin = DsFindPin.ByDirection(m_sampleGrabber as IBaseFilter, PinDirection.Output, 0);
}
else
{
videoOutPin = DsFindPin.ByDirection(m_captureDevice , PinDirection.Output, 0);
}

if (videoOutPin == null)
throw new Exception("Could not query the video output pin on source filter");

/* Intelligently connect the pins in the graph to the renderer */
hr = m_graph.Render(videoOutPin);

Marshal.ReleaseComObject(videoOutPin);


Jan 26, 2012 at 1:53 PM

If the only you need is to capture bitmaps, I would recommend you to use AForge framework: http://www.aforgenet.com/

The capturing code would look like this:

var cam = new FilterInfoCollection(FilterCategory.VideoInputDevice).First();
cam.DeiredFrameSize = ...
cam.DesiredFrameRate = ...
cam.NewFrame += (object sender, AForge.Video.NewFrameEventArgs eventArgs)...
cam.Start();