我开发了DirectShow C ++应用程序,它成功地将网络摄像头视图预览到提供的窗口中。现在我想从这个实时网络摄像头预览中捕获图像。我已经使用了图形管理器,ICaptureGraphBuilder2,IMoniker等。 我搜索并找到以下选项: WIA&样品采集器。 许多人建议使用SampleGrabber,但根据MS的msdn文档SampleGrabber已弃用,不应使用。而且我不想使用WIA API。
那么哪种DirectShow最佳方式可以从实时网络摄像头预览中捕获图像?
答案 0 :(得分:3)
以下是DxSnap sample from DirectShow.NET library的引用:
使用DirectShow从捕获的Still引脚拍摄快照 设备。请注意,MS会鼓励您使用WIA,但如果您这样做 想要使用DirectShow和C#,这是怎么做的。
请注意,此示例仅适用于输出的设备 未压缩的视频为RBG24。这将包括大多数网络摄像头,但 可能是零电视调谐器。
这是C#代码,但你应该明白接口是完全相同的。关于如何在C ++中使用Sample Grabber Filter
还有其他示例。
不推荐使用示例Grabber,从几个最新的SDK中删除标题,但是运行时组件都在那里,并且将在那里存在很长时间,否则会破坏大量应用程序(例如视频聊天)在浏览器托管的GMail正在使用Sample Grabber)。因此,基本上,Sample Grabber仍然是一种从网络摄像头捕获快照的简单方法,或者如果您更喜欢使用最新的MS API - 您可能需要查看Media Foundation( 2016年7月9日更新:新的Windows Server安装可能需要一个添加“Media Foundation”和/或“桌面体验”功能,以使Media Foundation API与DirectShow一起使用,而DirectShow编辑服务,Sample Grabber是其中的一部分。默认安装不提供qedit .dll开箱即用)。
同样在C ++中,您当然不必使用Sample Grabber Filter。您可以使用DirectShow BaseClasses开发自定义过滤器作为自定义转换过滤器或自定义渲染器,它们接受传入的视频源并从DirectShow管道导出帧。另一种选择是使用来自旧版SDK之一的Sample Grabber示例源代码(这不是OS Sample Grabber的确切来源,但它正在做同样的事情)。然而,与Windows一起提供的Sample Grabber仍然是一个不错的选择。
答案 1 :(得分:1)
在微软网站上列出的是如何使用IVMRWindowlessControl9 :: GetCurrentImage捕获帧的示例......以下是一种方法:
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's 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!
答案 2 :(得分:1)
如果捕获滤波器有2个引脚,则很可能是捕获引脚和静止引脚。在这种情况下,你仍然需要一个连接到信号源捕捉引脚的Smart Tee,并且需要预览智能T形接头的预览引脚,并从智能T形接头的引脚上捕捉样品。
(如果您不知道SmartTee是什么,它是一个过滤器,可以播放分配器技巧,只有当捕获引脚没有超级陷入困境时才会向预览引脚发送样本。它的工作是提供一个路径要渲染的VMR不会破坏捕获过滤器和捕获过滤器下游过滤器之间的分配器。
如果捕获过滤器同时具有捕获和预览引脚,我认为您可以找出您需要做的事情。
无论如何,摘要:SampleGrabber只是一个CTransInPlaceFilter。您也可以将它写为Null渲染器,只需确保在CheckInputType中填写一些垃圾,然后在DoRenderSample中调用回调。