zoukankan      html  css  js  c++  java
  • DirectShow应用——视频捕捉WDM Vs VFW

    说起视频捕捉问题我们先要来看一下视频捕捉卡。根据使用的驱动程序的不同来分类,目前市场上大致有两种捕捉卡:VFW (Video for Windows)卡和WDM (Windows Driver Model)卡。前者是一种趋于废弃的驱动模型,而后者是前者的替代模型;WDM还支持更多新的特性,比如直接支持电视接收、视频会议、1394接口的设备、桌面摄像机、多条视频流(Line-21或Closed-Caption等)同时输出等等。采用VFW的一般都是些以前生产的卡;市面上新出现的,一般都是采用了WDM驱动程序。另外,视频捕捉卡的接口,可以是以PCI或AGP的方式插入PC机箱,也可以直接以USB接口的方式外挂;还有就是通过1394接口与PC机相连的数码摄像机等等。

    使用DirectShow来处理一般的视频捕捉问题,是相对比较简单的。这当然得益于DirectShow这一整套先进的应用架构。捕捉卡通常也是以一个(Capture) Filter的形式出现的。处理视频捕捉,我们同样是使用Filter Graph,同样是操作Filter;控制起来,就似于操作媒体文件的播放。当然,这主要是从应用程序控制层面上来说的;视频捕捉的应用场合比较多,视频捕捉本身的一些处理还是有它的特殊性的,而且牵涉面比较广。本文侧重于阐述一个建立视频捕捉程序的一般过程,以及WDM与VFW的兼容性问题。

    当视频捕捉卡正确安装到系统中后,使用GraphEdit插入Filter,我们可以在“Video Capture Sources”目录下看到代表捕捉卡的那个Filter。一般一个Capture Filter至少有一个Capture Output Pin;典型的情况下,还有一个Preview Pin或者Video Port Pin(一般Preview Pin和VP Pin不会共存)。有些视频捕捉卡,能够同时捕捉Video和Audio,那么它的Filter自然还应该有Audio部分的输出Pin。视频捕捉卡都注册在CLSID_VideoInputDeviceCategory目录之下;要知道系统中安装了哪些捕捉卡,需要利用系统枚举,如下:
    ICreateDevEnum *pDevEnum = NULL;
    IEnumMoniker *pEnum = NULL;
    // Create the System Device Enumerator.
    HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
        CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,
        reinterpret_cast<void**>(&pDevEnum));
    if (SUCCEEDED(hr))
    {
        // Create an enumerator for the video capture category.
        hr = pDevEnum->CreateClassEnumerator(
            CLSID_VideoInputDeviceCategory, &pEnum, 0);
    }
    Capture Filter的创建也不是象其他Filter一样使用CoCreateInstance,而是在枚举的过程中BindToObject。在这一点上,对WDM卡和VFW卡的处理是一致的。

    将Capture Filter加入Filter Graph之后,剩下的Filter怎么连接?DirectShow给我们提供了一个简单的解决方法:使用ICaptureGraphBuilder2接口。如下创建:
    IGraphBuilder *pGraph = 0;
    ICaptureGraphBuilder2 *pBuild = 0;
    // Create the Capture Graph Builder.
    HRESULT hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, 0,
         CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2,
         (void**)&pGraph);    
    if (SUCCEEDED(hr))
    {
        // Create the Filter Graph Manager.
        hr = CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER,
            IID_IGraphBuilder, (void**)&pGraph);
        if (SUCCEEDED(hr))
        {
            // Initialize the Capture Graph Builder.
            pBuild->SetFiltergraph(pGraph);
        }
    }
    接下来,就是使用ICaptureGraphBuilder2::RenderStream来继续各个Output Pin的连接。值得注意的是,这里有一个Pin Category的概念,作为RenderStream的第一个参数,比如Preview Pin的目录为PIN_CATEGORY_PREVIEW,Capture Pin的目录为PIN_CATEGORY_CAPTURE等等。下面是Preview Pin的连接示例:
    ICaptureGraphBuilder2 *pBuild; // Capture Graph Builder
    // Initialize pBuild (not shown).
    IBaseFilter *pCap; // Video capture filter.
    /* Initialize pCap and add it to the filter graph (not shown). */
    hr = pBuild->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,
        pCap, NULL, NULL);
    调用RenderStream实现Preview链路,不管Capture Filter是否有Preview Pin或者只有VP Pin,Capture Graph Builder都能自动正确地处理。(如果只有VP Pin,则自动连接VP Pin;如果Capture Filter只有一个Capture Output Pin,则自动插入一个Smart Tee Filter然后再连接。)

    要实现视频捕捉到文件,最简单的方法也是使用ICaptureGraphBuilder2::RenderStream。如下(假设生成的是AVI文件):
    IBaseFilter *pMux;
    hr = pBuild->SetOutputFileName(
        &MEDIASUBTYPE_Avi,  // Specifies AVI for the target file.
        L"C:\\Example.avi", // File name.
        &pMux,              // Receives a pointer to the mux.
        NULL);              
    hr = pBuild->RenderStream(
        &PIN_CATEGORY_CAPTURE, // Pin category.
        &MEDIATYPE_Video,      // Media type.
        pCap,                  // Capture filter.
        NULL,                  // Intermediate filter (optional).
        pMux);                 // Mux or file sink filter.

    // Release the mux filter.
    pMux->Release();
    下面是典型的两个经过RenderStream以后构建的Capture Filter Graph的示意图:





    使用Capture Graph Builder构建Filter链路的好处,还在于它能自动加入Crossbar Filter(用于选择捕捉卡的输入端子,一般有三种:AV、S-Video、TV),如果是电视卡的话还有TV Tuner Filter等等;使用ICaptureGraphBuilder2::FindInterface就可以找到相应的控制接口等等。

    跟WDM卡相比,VFW卡实现的功能要简单得多。上述的Filter Graph创建过程,两种卡的处理是相似的;而对于视频捕捉的设置,则有较大的差异。WDM Capture Filter的执行文件为kswdmcap.ax,它实际上是kernel-mode下KsProxy的一个插件;而DirectShow使用了一个标识为CLSID_VfwCapture的Filter来支持VFW卡。WDM卡,设置Capture输出的图像格式、图像的对比度、亮度、色度、饱和度等,都是通过IAMStreamConfig、IAMVideoProcAmp等接口来实现(当然,在GraphEdit中可以通过Filter的Property Page来设置);而VFW卡,一般要将驱动程序内的设置对话框显示给用户。VFW驱动程序一般实现三个设置对话框:Video Source(设置图像源属性)、Video Format(设置图像输出格式)和Video Display(设置图像显示属性)。下面是显示Video Source对话框的示例:
    pControl->Stop(); // Stop the graph.
    // Query the capture filter for the IAMVfwCaptureDialogs interface.
    IAMVfwCaptureDialogs *pVfw = 0;
    hr = pCap->QueryInterface(IID_IAMVfwCaptureDialogs, (void**)&pVfw);
    if (SUCCEEDED(hr))
    {
        // Check if the device supports this dialog box.
        if (S_OK == pVfw->HasDialog(VfwCaptureDialog_Source))
        {
            // Show the dialog box.
            hr = pVfw->ShowDialog(VfwCaptureDialog_Source, hwndParent);
        }
    }
    pControl->Run();

    以上讲述了视频捕捉程序创建的一般过程。视频捕捉还有其他问题,比如AV同步、设备的热插拔、DV Camcorder的控制、Analog TV以及Digital TV的支持,还有捕捉后的音视频压缩、音视频合成等等。要想编写出专业级的视频捕捉程序,这些问题是不可回避的!

    http://www.haogongju.net/art/561272

  • 相关阅读:
    【第40套模拟题】【noip2011_mayan】解题报告【map】【数论】【dfs】
    【模拟题(63550802...)】解题报告【贪心】【拓扑排序】【找规律】【树相关】
    【模拟题(电子科大MaxKU)】解题报告【树形问题】【矩阵乘法】【快速幂】【数论】
    IMemoryBufferReference and IMemoryBufferByteAccess
    SoftwareBitmap and BitmapEncoder in Windows.Graphics.Imaging Namespace
    Windows UPnP APIs
    编译Android技术总结
    Windows函数转发器
    Two Ways in Delphi to Get IP Address on Android
    Delphi Call getifaddrs and freeifaddrs on Android
  • 原文地址:https://www.cnblogs.com/wqj1212/p/2438821.html
Copyright © 2011-2022 走看看