我已经开发了DirectShow C++应用程序,它成功地预览网络摄像头视图到提供的窗口。现在我想要从这个实时网络摄像头预览捕获图像。为此,我使用了图形管理器、ICaptureGraphBuilder2、IMoniker等。我已经搜索并找到以下选项: WIA和样本抓取。许多人建议使用SampleGrabber,但根据MS的msdn文档,SampleGrabber已被弃用,不应使用。而且我不想使用WIA API。
那么从实时网络摄像头预览中捕获图像的最佳DirectShow方式是什么呢?
发布于 2012-07-10 02:20:04
下面是DxSnap sample from DirectShow.NET library的一句话:
使用DirectShow从捕获设备的静止引脚拍摄快照。注意MS鼓励你使用WIA来做这件事,但是如果你想使用DirectShow和C#,这里有方法。
请注意,此示例仅适用于将未压缩的视频输出为RBG24的设备。这将包括大多数网络摄像头,但可能没有电视调谐器。
这是C#代码,但您应该明白其中的含义,因为这些接口都是相同的。还有其他关于如何在C++中使用Sample Grabber Filter的示例。
Sample Grabber被弃用,标题从几个最新的SDK中删除,但是运行时组件都在那里,并且将在那里存在很长一段时间,否则许多应用程序将被破坏(例如,浏览器托管的GMail中的视频聊天正在使用Sample Grabber)。所以基本上样本抓取仍然是一个简单的方法来捕获从网络摄像机的快照,或者如果你或者更喜欢遵循最新的make你会想看看媒体基础(2016年7月9日更新:新的Windows Server安装可能需要一个添加“媒体基础”和/或“桌面体验”的功能,使媒体基础API可与DirectShow,和DirectShow编辑服务,样本抓取是其中的一部分。默认安装不提供现成的qedit.dll )。
同样,在C++中,你当然不需要使用样本抓取过滤器。您可以使用DirectShow BaseClasses开发自定义筛选器作为自定义转换筛选器或自定义渲染器,它们接受传入的视频源并从DirectShow管道中导出帧。另一种选择是使用旧SDK中的示例Grabber示例源代码(这不是OS示例Grabber的确切源代码,但它做的是相同的事情)。然而,Windows附带的示例Grabber仍然是一个很好的选择。
发布于 2012-07-31 09:42:35
微软网站上列出了一个如何使用IVMRWindowlessControl9 Control9::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!发布于 2014-02-13 15:02:57
天啊..。这么多的错误信息。如果您在directshow图形中预览,则这取决于您要预览的内容。捕获过滤器有1个、2个或3个针脚。如果它有一个引脚,它很可能是一个“捕获”引脚(没有预览引脚)。为此,如果您想要同时捕获和预览,您应该放入一个“智能T形”过滤器,并将VMR从预览引脚上连接下来,并从捕获引脚上钩起“能抓取帧的东西”。因为你不想浪费DirectShow糟糕的引脚开始/停止的东西(相反,只是简单地控制整个图形的开始/停止状态)。你不需要使用SampleGrabber,它是一个非常简单的过滤器,你可以在几个小时内编写它(我应该知道,我是编写它的人)。它只是一个CTransInPlace过滤器,你可以设置一个强制的媒体类型让它接受,你还可以在它上面设置一个回调接口,当它收到一个样本时回调你。实际上,编写一个在接收到示例时回调您的NullRenderer会更简单,您可以很容易地编写此代码。
如果捕获过滤器有两个引脚,则很可能是一个捕获引脚和一个静止引脚。
(如果您不知道什么是SmartTee,那么它是一个过滤器,它会玩分配器的把戏,只有在捕获引脚没有完全瘫痪的情况下才会将样本发送到预览引脚。它的工作是为VMR提供一条渲染路径,从中不会搞砸捕获过滤器和捕获过滤器下游的过滤器之间的分配器)
如果捕获过滤器同时具有捕获和预览引脚,我认为您可以确定需要执行的操作。
总之,总结: SampleGrabber只是一个CTransInPlaceFilter。你也可以把它写成一个空的渲染器,只要确保在CheckInputType中填入一些垃圾,并在DoRenderSample中回调你的回调即可。
https://stackoverflow.com/questions/11398758
复制相似问题