2

The application is implemented in C# using DirectShowLib and a USB camera (Logitech C930e). The graph is compiled using RenderStream method. SmartTee filter is automatically generated as there is no preview pin provided.

RenderStream is called once for preview and then for capture. However, it fails to connect the second call to the SmartTee even if swapped (capture then preview). The error handler thrown is: -2147024809 (0x80070057; E_INVALIDARG; The parameter is incorrect)

code snippet as follows

    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 below shows the remote connection to the graph. The graph runs fine by manually linking SmartTee capture to MuxFilter within GraphEdit.

Any hints regarding the possible error cause will be very much appreciated.

A Obaidi
  • 23
  • 5

1 Answers1

1

Without seeing the actual call to ICaptureGRaphBuilder2.RenderStream, I can only make some assumptions about the E_INVALIDARG error. However, from the remote connection to the graph, I can see that there is something terribly wrong with your graph. Two output pins shouldn't be connected to the same input pin. You should always call the RenderStream for the Capture path first, because it's the Capture pin that negotiates the media type. You already have Capture pin on your source filter (even 2 of them why?). I think that you need to call your Capture RenderStream like this:

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

Where: pSource is the IBaseFilter interface of the Video Camera Terminal CapFilter, pMux is the IBaseFilter interface to the MuxFilter (there should be only one MuxFilter added to the graph!), pWriter is the IBaseFilter interface to the Writer filter (interview.avi).

You should add only one instance of the Video Camera Terminal CapFilter, only one instance of the MuxFilter (AVI Mux) and only one instance of the File Writer filter (interview.avi). With this setup the RenderStream call for the Capture path should succeed. After that you can try calling RenderStream for the preview path and the Smart tee should be added if not already added with the first call. Let me know if I can help you further with this.

VuVirt
  • 1,887
  • 11
  • 13
  • Many thanks for your reply and help offer. I have added a code snippet for more clarity. You could be probably right about calling RenderStream for Capture first. However, in my case, I need to preview the video in my application first then the capture will be added by the user if needed. The sequence that generate the above graph is [1]-[2]-[3]-[1] or [1]-[2]-[1]-[3]. My current dirty remedy is by adding a manual graph building for the second preview call. This sequence [1]-[2]-[3]-[4] is working. – A Obaidi Oct 04 '16 at 13:22
  • 1-2-3-4 looks ok at first glance. Otherwise if you need to optimize it (if at all possible) you can try rebuilding the whole graph, by removing all filters and re-adding them and then do RenderStream(Capture...) and RenderStream(Preview...) when the user decides to include capture to the preview. – VuVirt Oct 04 '16 at 13:47
  • What is the best way to remove the existing graph? – A Obaidi Oct 04 '16 at 16:28
  • Remove all filters and then Release the graph. Only Release should also work. – VuVirt Oct 04 '16 at 16:30