4

我正在尝试使用 GMFBuilder,以便我可以预览来自网络摄像头的流并定期保存,而无需重新启动整个图表。但是我不确定这是否正确,我试图按照示例进行操作,但代码已更新并且情况发生了变化。

我尝试创建:

WEbcam -> Smart Tee (preview) -> AVI Decompressor -> Video Renderer
          Smart Tee (Capture) -> BridgeSinkFilter

并且:

BridgeSourceFilter -> ffdshow video encoder -> haali mastroska muxer 

(只是因为它易于使用)

关于让代码正常运行的输入将不胜感激。

    private void button2_Click(object sender, EventArgs e)
    {
        IGraphBuilder firstGraph = (IGraphBuilder)new FilterGraph();
        IGraphBuilder secondGraph = (IGraphBuilder)new FilterGraph();

        IBaseFilter BridgeSinkFilter;
        IBaseFilter BridgeSourceFilter;

        IBaseFilter Source;
        IBaseFilter Mux;
        IBaseFilter FileWriter;

        IGMFBridgeController bridge = (IGMFBridgeController)new GMFBridgeController();

        bridge.AddStream(1, eFormatType.eMuxInputs, 1);

        BridgeSinkFilter = (IBaseFilter)bridge.InsertSinkFilter(firstGraph);

        Source = FindFilter(FilterCategory.VideoInputDevice, "SG330");
        firstGraph.AddFilter(Source, "source");

        IBaseFilter SmartTee = FindFilter(FilterCategory.LegacyAmFilterCategory, "Smart Tee");
        firstGraph.AddFilter(SmartTee, "Smart Tee");

        IPin pinin, pinout;

        pinout = FindPinByDirection( Source, PinDirection.Output);
        pinin = FindPinByDirection( SmartTee, PinDirection.Input);

        firstGraph.Connect(pinout, pinin);
        pinout = FindPinByDirection(SmartTee, PinDirection.Output);
        pinin = FindPinByDirection(BridgeSinkFilter, PinDirection.Input);

        firstGraph.Connect(pinout, pinin);

        IBaseFilter Decomp = FindFilter(FilterCategory.LegacyAmFilterCategory, "AVI Decompressor");
        firstGraph.AddFilter(Decomp, "Avi Decompressor");

        pinout = FindPinByDirection(SmartTee, PinDirection.Output);
        pinin = FindPinByDirection(Decomp, PinDirection.Input);

        firstGraph.Connect(pinout, pinin);

        IBaseFilter Renderer = FindFilter(FilterCategory.LegacyAmFilterCategory, "Video Renderer");
        firstGraph.AddFilter(Renderer, "Video Renderer");

        pinout = FindPinByDirection(Decomp, PinDirection.Output);
        pinin = FindPinByDirection(Renderer, PinDirection.Input);

        firstGraph.Connect(pinout, pinin);

        DsROTEntry g = new DsROTEntry(firstGraph);

        BridgeSourceFilter =  (IBaseFilter)bridge.InsertSourceFilter(BridgeSinkFilter, secondGraph);
        DsROTEntry h = new DsROTEntry(secondGraph);

        IBaseFilter Muxe = FindFilter(FilterCategory.VideoCompressorCategory, "ffdshow video encoder");
        secondGraph.AddFilter(Muxe, "Mux");

        pinout = FindPinByDirection(BridgeSourceFilter, PinDirection.Output);
        pinin = FindPinByDirection(Muxe, PinDirection.Input);

        secondGraph.Connect(pinout, pinin);

        IBaseFilter MKV = FindFilter(FilterCategory.LegacyAmFilterCategory, "Haali Matroska Muxer");
        IFileSinkFilter fs = (IFileSinkFilter)MKV;
        fs.SetFileName("c:\\cool.mkv", null);

        secondGraph.AddFilter(MKV, "mux");

        pinout = FindPinByDirection(Muxe, PinDirection.Output);
        pinin = FindPinByDirection(MKV, PinDirection.Input);
        secondGraph.Connect(pinout, pinin);

        bridge.BridgeGraphs(BridgeSinkFilter, BridgeSourceFilter);



        IMediaControl mediacontrolforpartone = (IMediaControl)firstGraph;
        mediacontrolforparttwo = (IMediaControl)secondGraph;
        mediacontrolforpartone.Run();
        mediacontrolforparttwo.Run();

    }
4

1 回答 1

5

根据我目前的知识正确使用 GMFBridge:

从以下网址获取 GMFBridge DLL:http ://www.gdcl.co.uk/gmfbridge/ 从以下网址 获取 DirectShowLib DLL:https ://sourceforge.net/projects/directshownet/files/DirectShowNET/

将它们都包含在您的项目中。

创建 2 个图表。1 用于预览,2 用于捕获。

IGraphBuilder firstgraph = (IGraphBuilder) new FilterGraph();
IGraphBuilder secondgraph = (IGraphBuilder) new FilterGraph();

创建一个从 GMFBridge dll 连接两个图的桥

IGMFBridgeController Bridge = (IGMFBridgeController) new GMFBridgeController();

从这里您设置桥接器以允许多路输入

Bridge.AddStream(1, eFormatType.eMuxInputs, 1);

从这里你可以添加你的源视频过滤器,它不需要连接到网桥,添加 Smart Tee,并将源连接到 Smart Tee。

然后创建一个过滤器来容纳将完成工作的第一个桥式过滤器

BridgeSinkFilter = (IBaseFilter)Bridge.InsertSinkFilter(firstgraph);

此过滤器将持续接受来自 Smart Tee 捕获引脚的视频。如果第二个图桥过滤器已连接并正在运行,它将把视频从 BridgeSInkFilter 传递到第二个图。否则,它只是把它扔掉,但它总是在运行。

将 BridgeSinkFilter 连接到 Smart Tee 的捕获引脚。我发现连接引脚的最佳方法是使用https://splicer.svn.codeplex.com/svn/src/Splicer/Utilities/FilterGraphTools.cs的 FindPinByDirection然后调用

firstgraph.connect(pinoutput, pininput)

从这里,要预览视频,应该添加来自 FilterCategory.LegacyAmFilterCategory 的 AVI Decompressor 过滤器并将其连接到 Smart Tee 的 Preview 引脚。然后 Video Renderer 添加并连接到 AVI Decompressor。

那应该照顾第一张图。

第二张图需要从桥开始。它将从第一个图 bridgesinkfilter 创建一个桥,并将其拉到第二个图中,我们可以在其中做任何我们想做的事情。要做到这一点,我们需要桥的另一边。

IBaseFilter BridgeSourceFilter = (IBaseFilter)Bridge.InsertSourceFilter(BridgeSinkFilter,secondgraph);

这将源设置为第一个图中的 sinkfilter,但以 BridgeSourceFilter 的名义将其放在我们的第二个图中。

现在连接一个编码器、ffdshow 视频编码器等。将它连接到 BridgeSourceFilter。

添加多路复用器、AVI 多路复用器和文件编写器。连接它们。这就是第二张图的全部内容。

要完成图表,我们需要创建 2 个可以启动和停止图表的媒体控制器。

IMediaControl MediaControl_FirstGraph = (IMediaControl)firstgraph;
IMediaControl MediaControl_SecondGraph = (IMediaControl)secondgraph;

现在我们可以打电话了

MediaControl_FirstGraph.Run() to start previewing the video.

然后为了捕捉该视频,我们需要连接第一张图和第二张图之间的桥梁,然后运行第二张图。

Bridge.BridgeGraphs(BridgeSinkFilter,BridgeSourceFilter);
MediaControl_SecondGraph.Run()

在任何时候,您都可以通过断开桥接来停止捕获,然后停止第二个图表。

Bridge.BridgeGraphs(null, null);
MediaControl_SecondGraph.Stop();

我认为这涵盖了我对 GMF 桥控制的发现:)

希望这符合 Geraint Davies 的标准

如果第二张图的任何地方都存在最轻微的错误,那么当您运行第二张图时,它将停止第一张图。这是一个很好的迹象,有些事情是错误的。如果你给它一个无效的名字,比如让 Avi mux -> 文件编写器尝试保存在一个不真实的位置,它会停止图表

此代码将创建一个新窗口并将视频粘贴在该新窗口中。要将视频流式传输到表单的面板框中,您只需要添加 4 行代码。

IVideoWindow var = firstgraph as IVideoWindow();
var.put_Owner(panel1.handle);
var.put_windowstyle( windowstyle.child | windowstyle.clipchildren );
var.SetWindowPosition( panel1.clientrectangle.left, panel1.clientrectangle.top, panel1.clientrectangle.width, panel1.clientrectangle.height);    
于 2011-06-23T19:25:37.660 回答