delphidirectshowcitrixdspack

DSPack, Citrix and SetSyncSource()


I using Delphi XE and DSPack 2.3.3. I'm maintaining a desktop application with Webcam capture. The user is able to capture pictures of visitors and documents. Everything is working fine. One of our largest customers is moving to Citrix 7.13 and the webcam is freezing.

Their support contacted Citrix and Citrix Engineering would like to know if the application is calling the IMediaFilter::SetSyncSource method to explicitly set the “reference clock” to the filter graph in their code regarding the webcam capturing. I made a few test and in fact there's a call when the rendering starts. You can see the call when running DSPack demo "VideoCap":

  // now render streams
  with CaptureGraph as IcaptureGraphBuilder2 do
  begin
    // set the output filename
    SetOutputFileName(MEDIASUBTYPE_Avi, PWideChar(CapFile), multiplexer, Writer);

    // Connect Video preview (VideoWindow)
    if VideoSourceFilter.BaseFilter.DataLength > 0 then
      RenderStream(@PIN_CATEGORY_PREVIEW, nil, VideoSourceFilter as IBaseFilter,
        nil , VideoWindow as IBaseFilter);

    // Connect Video capture streams
    if VideoSourceFilter.FilterGraph <> nil then
      RenderStream(@PIN_CATEGORY_CAPTURE, nil, VideoSourceFilter as IBaseFilter,
        nil, multiplexer as IBaseFilter);

    // Connect Audio capture streams
    if AudioSourceFilter.FilterGraph <> nil then
    begin

      RenderStream(nil, nil, AudioSourceFilter as IBaseFilter,
        nil, multiplexer as IBaseFilter);
    end;
  end;
  CaptureGraph.Play; 

According to DSpack source comments:

{ The reference clock has changed. The filter graph manager sends this event
  when its IMediaFilter.SetSyncSource method is called.}
property OnGraphClockChanged: TNotifyEvent read FOnGraphClockChanged write FOnGraphClockChanged;

And in fact OnGraphClockChanged gets fired after CaptureGraph.Play is called.

Is it possible to avoid calling SetSyncSource? Do you know if this will solve this issue?

TIA, Clément


Solution

  • Quoting the MSDN page on IMediaFilter::SetSyncSource:

    When the graph runs, the Filter Graph manager calls this method on every filter in the graph, to notify them of the graph reference clock. Use this method to store the IReferenceClock pointer. Increment the reference count on the stored pointer. Before the filter is removed from the graph, the Filter Graph Manager calls SetSyncSource again with the value NULL.

    This means that SetSyncSource() is called regardless of your code. If the filter you are using is stalling because of the filter graph calling it's SetSyncSource() method, then this seems like a defect in the filter.

    In this case a potential workaround would be to create a wrapper filter around the capture filter in question and to forward all method calls except SetSyncSource(). But most likely the problem has other origin.

    My bet is that setting the reference clock to NULL will solve the problem. To do this you have to query IMediaFilter interface from IFilterGraph and call SetSyncSource(NULL). This will disable the entire timing for the graph and render every multimedia sample as fast as it is generated.

    More details on live source filter graphs can be found at this MSDN page - https://msdn.microsoft.com/en-us/library/windows/desktop/dd390645(v=vs.85).aspx