最近在下载到得directshow视频采集程序中,几乎所有的程序都不支持我的"无驱摄像头",nnd,我还以为是自己的摄像头有问题呢,但是在qq中可以用其进行视频聊天哦,所以就仔细看了看directshow中视频是如何采集的。看了之后才明白,原来无驱摄像头中只提供了videosource接口,因而不能直接与videorender相连进行视频的采集,而目前大多数有驱动的摄像头在驱动中提供了包括videosource——decompress——colorspaceconvert等在内的所有滤波图表设计,所以可以直接与videorender相连来进行视频采集。下面就把无驱摄像头的视频采集部分写出来。
DirectShow作为DirectX的一个子集,它为用户提供了强大、方便的多媒体开接口,并且它拥有直接操作硬件的能力,这使得它的效率远胜于用GDI等图形方式编写的多媒体程序。这里结合实践中运用DirectShow实现视频采集(WIN32) 来加深对DirectShow的理解和操作能力。
1.系统环境及开发环境
a.系统支持DirectX(Win 2K以上系统),本文中安装的是directx9.0b版本。这个版本的特点就是在其头文件中需要包含#include <dshow.h>。后续版本的directx已经将其去除了,如果使用的是其它版本的directx不用往下看了。不过修改后肯定是可以应用的。
b.VC++ 6.0
c.视频采集设备(如USB摄像头,本文以"无驱摄像头"为例)
2、滤波图表设计
对于一般的摄像头而言,在graphedit中显示的均是两层的滤波图表设计,而本文中"无驱摄像头"的滤波图表设计却设计到了四层。如图所示:
一般而言,中间的两层会由摄像头的驱动提供的,既然是"无驱摄像头",当然需要自己手动添加了。但是不同类型的无驱摄像头所需要的中间渲染过程并不全部相同,只要在第一个显示为"USB视频设备"的右边输出引脚,点击右键选择"Render Pin",如果幸运,系统会自动将中间缺少的滤波图表添加进来的,然后单击运行按钮,就可以看到效果了。
3、directshow采集方案
(1)在头文件中添加:
#pragma comment (lib,"Strmiids")
#pragma comment (lib,"quartz")
#include <dshow.h>
(2):设计滤波图表过程。红色部分为在原来文件中新增加的部分,可以看出,只要将需要的filter加进去,并设置好输入、输出引脚就可以了。
ICaptureGraphBuilder2 * pBuilder = NULL;
pGraph = NULL;
pMediaControl = NULL;
//枚举视频设备
ICreateDevEnum *pDevEnum = NULL;
CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
IID_ICreateDevEnum, (void **)&pDevEnum);
IEnumMoniker *pClassEnum = NULL;
pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pClassEnum, 0);
ULONG cFetched;
if (pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK)
{
pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pSrc);
pMoniker->Release();
}
pClassEnum->Release();
CoCreateInstance(CLSID_CaptureGraphBuilder2,0,CLSCTX_INPROC_SERVER,IID_ICaptureGraphBuilder2,(void**)&pBuilder);
CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&pGraph);
pBuilder->SetFiltergraph(pGraph);//设置滤波图表
pGraph->QueryInterface(IID_IMediaControl,(void**)&pMediaControl);
pGraph->AddFilter(pSrc,L"avi");//连接视频源,第一个filter
pPreview = NULL;
IBaseFilter * decompression;
IBaseFilter * colorspace;
IPin * pSourceOut;//定义输出引脚
IPin* pPreIn;//定义输入引脚
CoCreateInstance(CLSID_MjpegDec,0,CLSCTX_ALL,IID_IBaseFilter,(void**)&decompression);//声明第二个filter
CoCreateInstance(CLSID_Colour,0,CLSCTX_ALL,IID_IBaseFilter,(void**)&colorspace);//声明第三个filter
CoCreateInstance(CLSID_VideoRenderer,0,CLSCTX_ALL,IID_IBaseFilter,(void**)&pPreview);//声明第四个filter
if (pPreview != NULL)
{ //按顺序连接三个滤波图表,如果有多个,顺序连接即可
pGraph->AddFilter(decompression,L"decompression");
pSourceOut = FindPin(pSrc,PINDIR_OUTPUT);//按顺序找到输入、输出引脚,并连接
pPreIn = FindPin(decompression,PINDIR_INPUT);
pGraph->ConnectDirect(pSourceOut,pPreIn,NULL);
pGraph->AddFilter(colorspace,L"decompression");
pSourceOut = FindPin(decompression,PINDIR_OUTPUT);
pPreIn = FindPin(colorspace,PINDIR_INPUT);
pGraph->ConnectDirect(pSourceOut,pPreIn,NULL);
pGraph->AddFilter(pPreview,L"preview");
//连接引脚
pSourceOut = FindPin(colorspace,PINDIR_OUTPUT);
pPreIn = FindPin(pPreview,PINDIR_INPUT);
pGraph->ConnectDirect(pSourceOut,pPreIn,NULL);
//获取预览窗口
IVideoWindow * pViewWnd= NULL;
pPreview->QueryInterface(IID_IVideoWindow,(void**)&pViewWnd);
if (pViewWnd)
{
//设置预览窗口的拥有者
pViewWnd->put_Owner((long)m_hWnd);
pViewWnd->put_Left(1);
pViewWnd->put_Top(1);
//获取预览窗口风格
long style;
pViewWnd->get_WindowStyle(&style);
style = style & ~WS_CAPTION;
style = style & ~WS_DLGFRAME;
style = style & WS_CHILD;
pViewWnd->put_WindowStyle(style);
//设置预览窗口宽度和高度
CRect rc;
GetClientRect(rc);
pViewWnd->put_Height(rc.Height()-60);
pViewWnd->put_Width(rc.Width()-2);
}
pMediaControl->Run();
}
return TRUE; // return TRUE unless you set the focus to a control
}
3、记得在程序退出时关闭所有的com端口