Best DirectShow way to capture image from webcam preview? SampleGrabber is deprecated

I developed a DirectShow C ++ application that successfully views a webcam view in the provided window. Now I want to capture an image from this webcam preview. For this, I used the graph manager, ICaptureGraphBuilder2, IMoniker, etc. I searched and found the following options: WIA and Sample Grabber. Many recommend using SampleGrabber, but according to MS msdn, SampleGrabber is deprecated and should not be used. And I do not want to use the WIA API.

So what is the best DirectShow way to capture image from webcam preview?

+4
source share
3 answers

Here is a quote from the DxSnap Example from the DirectShow.NET library :

Use DirectShow to create snapshots from the pins of the Still device. Note that MS recommends you use WIA for this, but if you want to do with DirectShow and C #, here's how.

Note that this example will only work with devices that output uncompressed video as RBG24. This will include most webcams, but probably with a null TV tuner.

This is C # code, but you should understand that all interfaces are the same. And there are other examples of how to use Sample Grabber Filter in C ++.

The Grabber example is outdated, the headers have been removed from the last few SDKs, however, the runtime components will all be there for a long time, otherwise many applications may be broken (for example, video chat in the browser used by GMail uses Sample Grabber). So basically Sample Grabber is still an easy way to capture snapshots from a webcam or, if you prefer to follow the latest MS APIs, you'd like to look at the Media Foundation ( July 9, 2016 update : to install Windows Server, maybe , you will need to add the “Media Foundation” and / or “Desktop Experience” features in order to access the Media Foundation API with DirectShow, as well as for DirectShow editing services, Sample Grabber. The default installation does not offer qedit.dll out of the box).

Also in C ++ you, of course, do not need to use the Sample Grabber Filter. You can create a custom filter using DirectShow BaseClasses to become a custom transform filter or custom visualizer that accepts an incoming video stream and exports frames from the DirectShow pipeline. Another option is to use the source code for a sample Grabber sample from one of the old SDKs (which is not the exact source for the Grabber example for the OS, but it does the same). However, the Sample Grabber shipped with Windows is still a good option.

+3
source

Listed on the Microsoft website is an example of how to capture a frame using IVMRWindowlessControl9 :: GetCurrentImage ... Here is one way to do this:

 IBaseFilter* vmr9ptr; // I'm assuming that you got this pointer already IVMRWindowlessControl9* controlPtr = NULL; vmr9ptr->QueryInterface(IID_IVMRWindowlessControl9, (void**)controlPtr); assert ( controlPtr != NULL ); // Get the current frame BYTE* lpDib = NULL; hr = controlPtr->GetCurrentImage(&lpDib); // If everything is okay, we can create a BMP if (SUCCEEDED(hr)) { BITMAPINFOHEADER* pBMIH = (BITMAPINFOHEADER*) lpDib; DWORD bufSize = pBMIH->biSizeImage; // Let create a bmp BITMAPFILEHEADER bmpHdr; BITMAPINFOHEADER bmpInfo; size_t hdrSize = sizeof(bmpHdr); size_t infSize = sizeof(bmpInfo); memset(&bmpHdr, 0, hdrSize); bmpHdr.bfType = ('M' << 8) | 'B'; bmpHdr.bfOffBits = static_cast<DWORD>(hdrSize + infSize); bmpHdr.bfSize = bmpHdr.bfOffBits + bufSize; // Builder the bit map info. memset(&bmpInfo, 0, infSize); bmpInfo.biSize = static_cast<DWORD>(infSize); bmpInfo.biWidth = pBMIH->biWidth; bmpInfo.biHeight = pBMIH->biHeight; bmpInfo.biPlanes = pBMIH->biPlanes; bmpInfo.biBitCount = pBMIH->biBitCount; // boost::shared_arrays are awesome! boost::shared_array<BYTE> buf(new BYTE[bmpHdr.bfSize]);//(lpDib); memcpy(buf.get(), &bmpHdr, hdrSize); // copy the header memcpy(buf.get() + hdrSize, &bmpInfo, infSize); // now copy the info block memcpy(buf.get() + bmpHdr.bfOffBits, lpDib, bufSize); // Do something with your image data ... seriously... CoTaskMemFree(lpDib); } // All done! 
+1
source

jeez ... so much dis info. if you are viewing a directshow chart, it depends on what you are viewing. Capture filters have 1, 2 or 3 pins. If it has 1 pin, it is most likely a “grabbing” pin (without preliminary pin). To do this, if you want to capture and preview at the same time, you must install the “Smart Tee” filter and connect the VMR to the preview output and connect “what captures frames” from the capture pin. since you don’t want to spoof using DirectShow crummy pin start / stop stuff (instead, just control the entire start / stop state of the chart). You do not need to use SampleGrabber, it is a simple filter and you could write it in a few hours (I should know that I wrote this). it's just a CTransInPlace filter, which you can set for a forced media type so that it can accept, and you can set a callback interface on it to call you back when it receives a sample. It’s actually easier to write a NullRenderer that will call you back when it receives the sample, you can write this quite easily.

If the capture filter has 2 pins, it is most likely a gripping pin and a fixed pin. in this case, you still need a smart tee connected to the output to connect the source, and it needs to preview the smart preview pin and capture the samples from the smart tee.

(If you don’t know what SmartTee is, it is a filter that plays distributor tricks and sends only the sample down to the preview contact if the capture contact is not too clogged. This task is to provide a path for the VMR to render from which the distributors will not load between the capture filter and the filters after the capture filter)

If the capture filter has both capture and preview, I think you can figure out what you need to do.

Anyway, the summary: SampleGrabber is just CTransInPlaceFilter. You could write it as a Null Renderer, just remember to fill some trash in CheckInputType and call the callback back to DoRenderSample.

+1
source

All Articles