2012-07-09 108 views
4

我开发了DirectShow C++应用程序,该应用程序已成功将Web Cam视图预览到提供的窗口中。现在我想从这个实时网络摄像头预览中捕捉图像。我已经使用图表管理器,ICaptureGraphBuilder2,IMoniker等。 我已搜索并找到以下选项: WIA &样品采集卡。 许多人建议使用SampleGrabber,但根据MS的msdn文件SampleGrabber已弃用,且不应使用。我不想使用WIA API。最好的DirectShow方法从网络摄像头预览捕捉图像? SampleGrabber已弃用

那么哪个是最好的DirectShow方法来捕捉实时网络摄像头预览图像?

回答

3

这里是DxSnap sample from DirectShow.NET library报价:

使用DirectShow拍摄快照从捕捉 设备的静止针。注意MS鼓励你使用WIA,但是如果你想使用DirectShow和C#来完成这个任务,你可以这样做。

请注意,此示例仅适用于将未压缩视频输出为RBG24的设备。这将包括大多数摄像头,但可能是零电视调谐器。

这是C#代码,但你应该明白接口都是一样的。还有关于如何在C++中使用Sample Grabber Filter的其他示例。

Sample Grabber已被弃用,头文件被从几个最新的SDK中移除,但是运行时组件都在那里,并且会在那里很长一段时间,否则许多应用程序将被破坏(例如Video在浏览器托管的Gmail中聊天使用Sample Grabber)。所以基本上,Sample Grabber仍然是一种简单的方法来捕捉网络摄像机的快照,或者如果您也可以选择遵循最新的MS API,您可能需要考虑Media Foundation(2016年7月9日更新:新的Windows Server安装可能会需要添加“媒体基础”和/或“桌面体验”功能以使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仍然是一个不错的选择。

+0

值得一提的是,链接的示例代码使用了Sample Grabber。而且,C++代码要简单得多,因为你有智能指针来管理引用计数。 – 2012-07-09 18:28:21

+0

Thanks Roman.R。我编写了WIA代码来捕捉图像几个小时,然后出现启动WIAVideo对象的错误,并发现[“WIA不支持Windows Server 2003,Windows Vista或更高版本中的视频设备。”](http:// msdn。 microsoft.com/en-us/library/ms630377(VS.85).aspx)。现在我认为唯一的选择是DirectShow,并使用不赞成使用的SampleGrabber。如此糟糕的MS。 – Shailesh 2012-07-10 10:48:49

+0

除了ISampleGrabber之外,使用DirectShow捕获图像的任何帮助。请... – Shailesh 2012-07-11 08:51:37

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! 
+0

这个来自哪里的链接将会很棒 – taxilian 2013-12-02 21:55:41

+0

微软提供的示例位于http://msdn.microsoft.com/en-us/library/windows/desktop/dd390541(v=vs.85).aspx微软的例子没有包含位图复制代码;我从旧版DirectX SDK中打包的示例中获得了该代码。 – AhiyaHiya 2013-12-04 22:17:55

1

哎呀......如此多的DIS信息。如果您正在预览directshow图表,那么这取决于您预览的内容。捕获滤波器有1个,2个或3个引脚。如果它有1个引脚,它很可能是一个“捕获”引脚(无预览引脚)。为此,如果您想同时捕捉和预览,则应该放入一个“Smart Tee”滤波器,并将VMR从预览引脚关闭,并将“抓取帧的东西”连接到捕捉引脚。因为你不想用DirectShow的糟糕的引脚启动/停止的东西(相反,只是简单地控制整个图形的启动/停止状态)。你不需要使用SampleGrabber,它是一个简单的过滤器,你可以在几个小时内写出它(我应该知道,我是写它的人)。它只是一个CTransInPlace过滤器,您可以设置一个强制媒体类型让它接受,并且您可以在其上设置一个回调接口,以在收到样本时回拨您。编写一个NullRenderer实际上更简单一些,当它收到一个样本时会调用你,你可以很容易地写出它。

如果捕获滤波器有2个引脚,它很可能是一个捕获引脚和一个静止引脚。在这种情况下,您仍然需要连接到信号源捕捉引脚的Smart Tee,并且需要预览智能发球台的预览引脚,并从智能tee的捕捉引脚捕捉样本。 (如果您不知道SmartTee是什么,它是一个过滤器,它会播放分配器技巧,并且只在捕获引脚没有超级陷阱时才向预览引脚发送样本。它的工作是提供一条路径对于VMR来说,从中不会弄碎捕获过滤器和捕获过滤器下游的过滤器之间的分配器)

如果捕获过滤器同时具有捕获和预览引脚,我想你可以找出你那么需要做。

无论如何,总结:SampleGrabber只是一个CTransInPlaceFilter。您也可以将它作为Null Renderer编写,只需确保在CheckInputType中填写一些垃圾,然后在DoRenderSample中调用回调。