zoukankan      html  css  js  c++  java
  • MSDN学习DirectShow——第四章 使用DirectShow 第一节 用graphedit模拟创建Graph

    第四章 使用DirectShow

     (本人英语也不算好,第一次翻译MSDN,希望对初学者有帮助,更快的学习。有不恰当的地方,请多多指出,我会尽早修改。)

    4.1 用graphedit模拟创建Graph

    (Simulating Graph Building with GraphEdit)

    DirectShow提供了一种叫做GraphEdit的调试公共程序,你可以用它来创建和测试filter graphs。

    4.1.1  graphedit概述

                       GraphEdit是一个可视化工具,可以创建filter graphs。通过GraphEdit,你可以在写程序代码前实验filter graph。你也可以加载一个你的程序创建的filter graph,来核实你的程序是否创建了正确的Graph。如果你开发一个定制的filter,GraphEdit提供了一种快速的方式测试它:简单的加载一个带有你定制的filter的graph,并且试着运行它。如果你是一个directShow的新手,GraphEdit是一个好的方式,熟悉filter graph和DirectShow架构。

             收下的插图显示了用GraphEdit怎么表示一个简单的filter graph。

    每一个filter用一个矩形来表示。在filter边缘的小的正方形代表pin。输入pin在filter的左边,输出pin 在右边。箭头代表pin之间的联结。

    使用GraphEdit,你可以:

    l  你可以使用一个可视的可拖放的界面来创建和修改filter graph。

    l  模拟编程调用来创建一个graph,例如IGraphBuilder::RenderFile。

    l  运行,暂停,停止 和搜索一个graph。

    l  看哪些filter已经在你的电脑上注册了,查看每一个filter的注册信息。

    l  观察filter的页面属性。

    l  观察pin连接的媒体类型。

    4.1.2  使用graphedit

             这一章包含了你可以使用graphedit 工具的做的一些事的简单介绍。要了解关于这些特征更详细的信息,请参照Graphedit程序的帮助文档。

    创建一个文件播放graph

    Graphedit可以创建一个文件播放 的filter graph。这个特点是与在一个程序中调用IGraphBuilder::RenderFile的方法有同样的作用。在【File】菜单中,点击【Render Media File】。Graphedit显示了Open File对话框。选择一个多媒体文件并点击【Open】。GraphEdit创建了一个filter graph来播放这个你选择的文件。

             你也可以render一个位于url上的媒体文件。从【file】菜单上,点击【Render URL】,Graphedit显示了一个对话框,可以输入URL。

    创建一个定制的Filter Graph

             GraphEdit 可以创建一个定制的filter graph,使用您的系统中已经注册的一些fiters。从【Graph】菜单中,点击【Insert Filter】。一个根据filter类型组织的你的系统中的filter的列表的对话框,显示出来。GraphEdit创建了这个列表根据你的注册表信息。下图显示了此对话框。

             添加一个filter到graph中,选择filter的名字,并点击【Insert Filters】按钮,或者双击filter的名字。你添加了filter以后,你可以连接两个filter,通过从一个filter的output pin 拖放鼠标到另一个filter的 input pin。如果pin接受了连接,Graphedit画一个箭头来连接他们。

    运行graph

    一旦你已经在graphedit中 创建了一个filter graph,你可以运行这个graph,看到它是否可以像你期望的那样工作。Graph菜单包含了播放,暂停和停止命令的菜单。这些命令分别调用了IMediaControl的Run,Pause,Stop方法。GraphEdit的工具栏有这些命令的按钮如下:

    注意:GrhphEdit 停止命令(Stop)停止了graph,并且把时间定位为0(假定graph是可定位的)。对于文件回放,这个动作重置了视频窗口到第一帧。然后调用 IMediaControl::Stop

           如果graph是可定位的,你可以拖动滑动条来定位。拖动滑动条调用了IMediaSeeking::SetPositions方法。

    查看属性页

             一些filter支持定制属性页,它提供了设置属性的用户界面。在graphEdit中查看一个filter的属性页,右键点击filter,并在弹出窗口中选择【Properties】。Graphedit显示一个属性页包含此filter定义的属性表。此外,GraphEdit 包含了所有在filter上pin的属性表。Pin属性表被graphedit定义,不是被filter定义。如果pin被连接了,pin的属性表显示连接的媒体类型。另外,它列出了pin的首选媒体类型。

    4.1.3  从外部过程加载一个graph

    Graphedit可以载入一个由外部程序创建的filter graph 。利用这个特点,你可以精确的看到你的程序创建的filter graph,只有少量的额外的代码在你的程序中。

    注意:这个特点需要windows 2000,windows XP,或者更新的版本。

    注意:从Windows Vista开始,你必须注册proppage.dll才能使这个功能能用。

    程序必须在运行对象表(Running Object Table(ROT))中注册filter graph实例。ROT是一个全局可查找的表保持运行跟踪。对象在ROT中用别名注册。为了连结graph,GraphEdit查找了ROT中显示名称与特有格式匹配的别名:

    !FilterGraph X pid Y

    X是十六进制的fiter graph manager的地址, Y是过程ID,也是十六进制的。

    当你的程序第一次创建fiter graph,调用下面的函数。

    HRESULT AddToRot(IUnknown *pUnkGraph, DWORD *pdwRegister) 
    {
        IMoniker * pMoniker = NULL;
        IRunningObjectTable *pROT = NULL;
     
        if (FAILED(GetRunningObjectTable(0, &pROT))) 
        {
            return E_FAIL;
        }
        
        const size_t STRING_LENGTH = 256;
     
        WCHAR wsz[STRING_LENGTH];
        StringCchPrintfW(wsz, STRING_LENGTH, L"FilterGraph %08x pid %08x", (DWORD_PTR)pUnkGraph, GetCurrentProcessId());
        
        HRESULT hr = CreateItemMoniker(L"!", wsz, &pMoniker);
        if (SUCCEEDED(hr)) 
        {
            hr = pROT->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, pUnkGraph,
                pMoniker, pdwRegister);
            pMoniker->Release();
        }
        pROT->Release();
        
        return hr;
    }

    这个函数创建了一个别名和一个新的ROT入门。第一个参数是一个指向filter graph的指针。第二参数接收一个识别新ROT入口的值。在程序释放filter graph前,调用以下的函数移除ROT入口。pdwRegister 这个参数是AddToRot函数返回的标识。

    void RemoveFromRot(DWORD pdwRegister)
    {
        IRunningObjectTable *pROT;
        if (SUCCEEDED(GetRunningObjectTable(0, &pROT))) {
            pROT->Revoke(pdwRegister);
            pROT->Release();
        }
    }

    以下的代码示例显示了怎么调用这些函数。在这个例子中,添加和删除ROT入口的代码是有条件编译的,因此只包含了调试版。

    IGraphBuilder *pGraph;
    DWORD dwRegister;
        
    // Create the filter graph manager.
    CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
                            IID_IGraphBuilder, (void **)&pGraph);
    #ifdef _DEBUG
    hr = AddToRot(pGraph, &dwRegister);
    #endif
     
    // Rest of the application (not shown).
     
    #ifdef _DEBUG
    RemoveFromRot(dwRegister);
    #endif
    pGraph->Release();

    在GraphEdit中查看filter graph,同时运行你的程序和graphedit。在GraphEdit【File】菜单中,点击【Connect to Remote Graph…】。在【Connect To Graph】对话框中,选择你程序的PID并点击【OK】。GraphEdit加载filter graph并显示。不要用其他的GraphEdit功能在这个graph中,可能会引用 不可预料的结果。例如,不要添加和删除filter,或者停止和开始graph。在退出程序前关闭graphEdit。

    注意:你的程序可能引起中断当它存在时。你可以忽略它们。

    下图显示了【Connect To Graph】对话框。

    GraphEdit加载一个graph,它在目标程序的环境中执行。因此,GraphEdit限制因为它在等待一个线程。例如,这在调试你的代码时可能发生。

    这个功能应该只用在调试版的程序中,不是发布版中,因为它可能使别程序查看或者控制filter graph。

    从命令行连接到一个远程graph

    GraphEdit支持命令行选项,加载一个远程Graph自动启动。语法是:

    GraphEdt -a moniker

    其中的moniker是一个用AddToRot函数先前创建和描述的。

     

    4.1.4  保存一个filter graph到graphedit文件中

    下面的代码例子显示了怎么保存一个filter graph 成.grf文件。这可能对你调试你的程序有用。

    HRESULT SaveGraphFile(IGraphBuilder *pGraph, WCHAR *wszPath) 
    {
        const WCHAR wszStreamName[] = L"ActiveMovieGraph"; 
        HRESULT hr;
        
        IStorage *pStorage = NULL;
        hr = StgCreateDocfile(
            wszPath,
            STGM_CREATE | STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
            0, &pStorage);
        if(FAILED(hr)) 
        {
            return hr;
        }
     
        IStream *pStream;
        hr = pStorage->CreateStream(
            wszStreamName,
            STGM_WRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE,
            0, 0, &pStream);
        if (FAILED(hr)) 
        {
            pStorage->Release();    
            return hr;
        }
     
        IPersistStream *pPersist = NULL;
        pGraph->QueryInterface(IID_IPersistStream, (void**)&pPersist);
        hr = pPersist->Save(pStream, TRUE);
        pStream->Release();
        pPersist->Release();
        if (SUCCEEDED(hr)) 
        {
            hr = pStorage->Commit(STGC_DEFAULT);
        }
        pStorage->Release();
        return hr;
    }

    例如,下面的代码创建了一个回放的graph和保存它成MyGraph.grf。

    void __cdecl main(void)
    {
        HRESULT hr;
        IGraphBuilder *pGraph;
        CoInitialize(NULL);
        
        // Create the Filter Graph Manager and render a file.
        CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, 
            IID_IGraphBuilder, reinterpret_cast<void**>(&pGraph));
        hr = pGraph->RenderFile(L"C:\\Video.avi", NULL);
     
        if (SUCCEEDED(hr))
        {
            hr = SaveGraphFile(pGraph, L"C:\\MyGraph.grf");
        }
        
        pGraph->Release();
        CoUninitialize();
    }

    关于StgCreateDocfile函数的更多信息,请查看SDK文档。

    4.1.5  加载一个可编程graphedit文件

    (Loading a GraphEdit File Programmatically )

    程序可以使用IPersistStream接口来加载一个grf文件,使用如下 的代码:

    HRESULT LoadGraphFile(IGraphBuilder *pGraph, const WCHAR* wszName)
    {
        IStorage *pStorage = 0;
        if (S_OK != StgIsStorageFile(wszName))
        {
            return E_FAIL;
        }
        HRESULT hr = StgOpenStorage(wszName, 0, 
            STGM_TRANSACTED | STGM_READ | STGM_SHARE_DENY_WRITE, 
            0, 0, &pStorage);
        if (FAILED(hr))
        {
            return hr;
        }
        IPersistStream *pPersistStream = 0;
        hr = pGraph->QueryInterface(IID_IPersistStream,
                 reinterpret_cast<void**>(&pPersistStream));
        if (SUCCEEDED(hr))
        {
            IStream *pStream = 0;
            hr = pStorage->OpenStream(L"ActiveMovieGraph", 0, 
                STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);
            if(SUCCEEDED(hr))
            {
                hr = pPersistStream->Load(pStream);
                pStream->Release();
            }
            pPersistStream->Release();
        }
        pStorage->Release();
        return hr;
    }

    注意: 在先前代码的IPersistStream::Load 函数能返回一个DirectShow错误或者成功的代码。想查看一系列返回值,去看Error 和 Success codes。

    GraphEdit文件仅被用作调试和调试。我们不打算用它来终端用户程序。

    更多StgIsStorageFile和StgOpenStorage函数的信息,请参照SDK文档。

  • 相关阅读:
    VS2017使用inet_ntoa()产生错误的解决方法
    ET框架:如何运行ET-Demo
    ProtoBuf入门
    AssetBundle入门
    UML图写法
    Visual Studio小技巧-引用项目外部的类
    UnityECS(一)UnityECS学习资料
    关于如何利用MySQL Workbench导入Excel表格
    SublimeText3插件安装(未完更新)
    Unity中Animator的2DSprite动画控制与使用
  • 原文地址:https://www.cnblogs.com/sdlypyzq/p/2505779.html
Copyright © 2011-2022 走看看