DirectShow Spy: Who Sent EC_ERRORABORT?

persiflage@stackoverflow asks if there is a chance to use DirectShow Spy see who sent an EC_ERRORABORT notification, which filter exactly. Let us see first why there is no way to find this out, and then we will see what we can do.

DirectShow Filter Graph Manager accepts events from filters via its IMediaEventSink interface. The conversation taking place around event notifications is like this:

  • Filter: Hey, Graph Manager! Can I call you IMediaEventSink?
  • Manager: Yes, you can.
  • F: I notify you on EC_ERRORABORT event, here is HRESULT that I have: VFW_E_SOMETHING.
  • M: OK.

Filter graph manager (FGM) does not ask “Who’s taking?”. It does not need to know, it accepts information anonymously. Can a non-filter post an event? Absolutely, FGM does not have to care. This is simple, but when a question raised who posted the event, there is no answer for it – there was no such information in first place.

The good news through is that a developer does not need one hundred percent precision. The source of the event is important to understand which of the filters aborted streaming, and any information is helpful. Spy impersonates the whole FGM and as such it is capable of covering IMediaEventSink interface as well, in order to trace calls to the log file, and, even more helpful, trace call stack of the call which brought specific event in.

With the call stack information at the time of event notification, the filter of interest can be identified pretty precisely. Especially, having debug symbols available, so that Spy could provide symbols for the code locations on stack.

For instance, let us looks at Windows SDK AMCap Sample which previews video and uses video renderer, and hence has EC_VIDEO_SIZE_CHANGED event involved (just an example, spy from now on traces EC_ERRORABORT call stack only). Once this event reaches FGM, the call stack logged is:

FilterGraphSpy.h(850): CSpyT<class CSpy,&struct _GUID const CLSID_FilterGraph>::Notify: nEventCode EC_VIDEO_SIZE_CHANGED (0x0A), nParameter1 0x00F00140, nParameter2 0x00000000
  DirectShowSpy!6a3ba3b4 CSpyT<CSpy,&CLSID_FilterGraph>::Notify (+ 337) [d:\projects\alax.info\repository-public\directshowspy\filtergraphspy.h, 859] (+ 13) @6a3a0000
  quartz!6a243188 CBaseFilter::NotifyEvent (+ 46) @6a220000
  quartz!6a3394f6 CBaseControlVideo::OnVideoSizeChange (+ 56) @6a220000
  quartz!6a2a2f9a CRenderer::CompleteConnect (+ 175) @6a220000
  quartz!6a337668 CRendererInputPin::CompleteConnect (+ 25) @6a220000
  quartz!6a23a470 CBasePin::ReceiveConnection (+ 213) @6a220000
  quartz!6a2a3741 CVideoInputPin::ReceiveConnection (+ 92) @6a220000
  ksproxy!65e94dc0 CBasePin::AttemptConnection (+ 84) @65e70000
  ksproxy!65e94e81 CBasePin::TryMediaTypes (+ 104) @65e70000
  ksproxy!65e94f68 CBasePin::AgreeMediaType (+ 115) @65e70000
  ksproxy!65e966a0 CBasePin::Connect (+ 100) @65e70000
  ksproxy!65e7d711 CKsOutputPin::Connect (+ 381) @65e70000
  quartz!6a23252e CFilterGraph::ConnectDirectInternal (+ 233) @6a220000
  quartz!6a23847c CFilterGraph::ConnectRecursively (+ 44) @6a220000
  quartz!6a238d09 CFilterGraph::ConnectInternal (+ 331) @6a220000
  quartz!6a238c22 CFilterGraph::Connect (+ 23) @6a220000
  DirectShowSpy!6a3b8686 CSpyT<CSpy,&CLSID_FilterGraph>::Connect (+ 881) [d:\projects\alax.info\repository-public\directshowspy\filtergraphspy.h, 672] (+ 0) @6a3a0000
  quartz!6a2322f0 CEnumMediaTypes::Release (+ 39) @6a220000
  qcap!6a6c7a31 CBuilder2_2::DoesCategoryAndTypeMatch (+ 408) @6a6b0000
  qcap!6a6b3424 _GUID_00000000_0000_0000_0000_000000000000 (+ 4) @6a6b0000
  qcap!6a6cb9cb CBuilder2_2::RenderStream (+ 5294) @6a6b0000
  AMCap!01009723 @01000000
  AMCap!010041be @01000000
  AMCap!01005e27 @01000000
  AMCap!0100611c @01000000
  AMCap!01007600 @01000000
  AMCap!010076ba @01000000
  AMCap!0100a90d @01000000

It does not take a rocket scientist to see that event is posted by video renderer hosted by quartz.dll, which was a part of pin connection handling, where a pin of ksproxy’s filter – which has to be WDM Video Capture Filter – was connected to video renderer input pin.

DirectShow Spy started logging new items:

  • COM interface calls on filter graph IMediaEvent, IMediaEventEx, IMediaEventSink interfaces
  • Call staclk on IMediaEventSink::Notify call, with EC_ERRORABORT code (other codes are logged without call stack to reduce hook overhead and avoid logging stuff for no reason)

Download links:

Leave a Reply