使用 DirectShow 预览时无法捕获相机源

Unable to capture a camera feed while previewing using DirectShow

该应用程序是使用 DirectShowLib 和 USB 摄像头 (Logitech C930e) 在 C# 中实现的。该图是使用 RenderStream 方法编译的。 SmartTee 过滤器是自动生成的,因为没有提供预览引脚。

RenderStream 被调用一次用于预览,然后用于捕获。但是,即使交换(捕获然后预览),它也无法将第二次调用连接到 SmartTee。抛出的错误处理程序是:-2147024809(0x80070057;E_INVALIDARG;参数不正确)

代码片段如下

    DirectShowLib.ISampleGrabber sg = null;
    DirectShowLib.ICaptureGraphBuilder2 cg = null;
    DirectShowLib.IGraphBuilder fg = null;

    IBaseFilter capFilter;
    IBaseFilter videoCompressorFilter;
    IBaseFilter muxFilter;
    IBaseFilter grabFilter;
    IBaseFilter VideoRendererFilter;

    Guid captureCat = PinCategory.Capture;
    Guid previewCat = PinCategory.Preview;
    Guid med = MediaType.Video;              

    DsGuid DSCaptureCat = (DsGuid)captureCat;
    DsGuid DSPreviewCat = (DsGuid)previewCat;
    DsGuid DSmed = (DsGuid)med;

    /*GetInterfaces*/
    Type comType = null;
    object comObj = null;
    fg = (IGraphBuilder)new FilterGraph();
    comType = Type.GetTypeFromCLSID(CgGuid);
    comObj = Activator.CreateInstance(comType);
    cg = (ICaptureGraphBuilder2)comObj; comObj = null;
    sg = (ISampleGrabber)new SampleGrabber();
    grabFilter = (IBaseFilter)sg;
    VideoRendererFilter = (IBaseFilter)new VideoRenderer();

    /*CreateCaptureDevice*/
    object capObj = null;
    capFilter = (IBaseFilter)capObj;

    /*SetupGraph*/
    hr = cg.SetFiltergraph(fg);

    if (renderFromDevice && deviceSet)
    {
        hr = fg.AddFilter(capFilter, "CapFilter");
    }

    AMMediaType media = new AMMediaType();
    media.majorType = MediaType.Video;
    media.subType = MediaSubType.RGB24;
    media.formatType = FormatType.VideoInfo;
    hr = sg.SetMediaType(media);

    DsUtils.FreeAMMediaType(media);
    media = null;


[1]
    /*RenderToScreen*/ 
    hr = fg.AddFilter(grabFilter, "FrameGrabFilter");

    hr = cg.RenderStream(DSPreviewCat, DSmed, capFilter, grabFilter, null);

[2]
    /*DerenderGraph*/
    if (renderFromDevice)
        removeDownstream(capFilter, videoCompressorFilter == null);
    else if (grabFilter != null)
        removeDownstream(grabFilter, true);

[3] 
    /*RenderToMovie*/
    videoFilename = Path.Combine(dirname, "interview.avi");

    cg.SetOutputFileName(MediaSubType.Avi, videoFilename, out muxFilter, out fileWriterFilter); //this automatically adds muxFilter to graph!

    string s;
    AMMediaType media = new AMMediaType();
    hr = fileWriterFilter.GetCurFile(out s, media);
    hr = fileWriterFilter.SetFileName(videoFilename, media);
    DsUtils.FreeAMMediaType(media);
    media = null;

    hr = fg.AddFilter(muxFilter, "MuxFilter"); //this adds the second muxFilter! now removed

    hr = cg.RenderStream(DSCaptureCat, DSmed, capFilter, null, muxFilter);

[4]     
    /*RenderToScreen2*/
    hr = fg.AddFilter(grabFilter, "FrameGrabFilter");

    hr = fg.AddFilter(VideoRendererFilter, "VideoRendererFilter");

    IEnumFilters enumFilters = null; 
    FilterInfo pInfo;
    IBaseFilter pFilter1, pFilter2, pFilter3;
    IPin outPin1, inPin1, outPin2, inPin2, inPin3;

    hr = fg.EnumFilters(out enumFilters);

    IBaseFilter[] filters = new IBaseFilter[1];
    int fetched;

    while (enumFilters.Next(1, filters, out fetched) == 0)
    {
        hr = filters[0].QueryFilterInfo(out pInfo);

        hr = fg.FindFilterByName("Smart Tee", out pFilter1);

        inPin1 = DsFindPin.ByDirection(pFilter1, PinDirection.Input, 0);
        outPin1 = DsFindPin.ByName(pFilter1, "Preview");

        hr = fg.FindFilterByName("FrameGrabFilter", out pFilter2);

        inPin2 = DsFindPin.ByDirection(pFilter2, PinDirection.Input, 0);
        outPin2 = DsFindPin.ByDirection(pFilter2, PinDirection.Output, 0);

        hr = fg.FindFilterByName("VideoRendererFilter", out pFilter3);

        inPin3 = DsFindPin.ByDirection(pFilter3, PinDirection.Input, 0);

        hr = fg.Connect(outPin1, inPin2);

        hr = fg.Connect(outPin2, inPin3);
    }

下面的 GraphEdit 显示了到图形的远程连接。通过在 GraphEdit 中手动将 SmartTee 捕获链接到 MuxFilter,图表运行良好。

任何关于可能的错误原因的提示将不胜感激。

没有看到对 ICaptureGRaphBuilder2.RenderStream 的实际调用,我只能对 E_INVALIDARG 错误做出一些假设。 但是,从与图形的远程连接来看,我可以看出您的图形存在严重错误。两个输出引脚不应连接到同一个输入引脚。 您应该始终首先为捕获路径调用 RenderStream,因为它是协商媒体类型的捕获引脚。您的源过滤器上已经有 Capture pin(为什么其中有 2 个?)。我认为您需要像这样调用您的 Capture RenderStream:

RenderStream(PIN_CATEGORY_CAPTURE, MEDIATYPE_Video, pSource, pMux, pWriter);

其中: pSource是Video Camera Terminal CapFilter的IBaseFilter接口, pMux 是 MuxFilter 的 IBaseFilter 接口(应该只有一个 MuxFilter 添加到图中!), pWriter 是 Writer 过滤器 (interview.avi) 的 IBaseFilter 接口。

您应该只添加一个 Video Camera Terminal CapFilter 实例、一个 MuxFilter (AVI Mux) 实例和一个 File Writer 过滤器实例 (interview.avi)。 使用此设置,捕获路径的 RenderStream 调用应该会成功。之后,您可以尝试为预览路径调用 RenderStream,如果智能 T 恤尚未在第一次调用时添加,则应添加。 如果我可以进一步帮助您,请告诉我。