最近在下载到得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端口

(oskycar)