DirectShow Grabber Sample for ISampleGrabber

I have a strange mistake with which I can not wrap my head. I have a graph created in a separate thread that runs, and I'm trying to access the IBaseFilter sampleGrabber outside the thread that worked in the console application, but I moved the code to a new project and where I try to use sampleGrabber to ISampleGrabber runtime complains null reference exception. If I am debugging sampleGrabber , it has the ISampleGrabber interface, but I can no longer use it. Moving the code inside a stream using a graph allows me to use it, but this is not ideal for my application.

How can a link exception be thrown by discarding what is explicitly from sampleGrabber to ISampleGrabber ?

+4
source share
2 answers

The problem is that DirectShow filters are early COM classes that implement a subset of COM in terms of reference counting, interfaces, nicknames, persistence - basically all the good things went on for years, but they completely ignore the apartments. DirectShow is multithreaded in itself, and it is typical that there is a control thread, and the streams of the streaming traffic flows are delayed. DirectShow concepts suggest that you can easily pass interface pointers between threads, and no marshaling is involved, expected, or required.

Then came .NET with COM shell checking, and DirectShow.NET with interfaces, as if they were full-featured COM pointers compatible with apartments. At the same time, Microsoft stopped giving DirectShow updates (for example, by supplying Sample Grabber with a free stream marshaller), and as a result, you got into a problem when in .NET you cannot do a simple thing with an interface pointer.

There is still no problem working with the API in your own code domain, since you can skip marshaling there and work with direct pointers.

You build a schedule in one apartment, and then get a call from Sample Grabber in another apartment (or, otherwise, in your scenario, you just do something on the workflow). You cannot use original interface pointers, especially. those in member variables because .NET runtime checking would check for apartment mismatch, especially when trying to marshal the interface pointer for another apartment.

If it was your custom filter with source code, you could add a custom IMarshal implementation or use the free stream marshaler to fix .NET on the native side of the code or otherwise add an assistant to pass the pointers around the apartments.

In the .NET code domain, the best approach would be to avoid working with pointers from multiple apartments. There may be a choice, but the easiest one that I think from the top of my head is

  • work in MTA in order to be able to have multiple threads accessing DirectShow interface pointers.
  • use CLSID_FilterGraphNoThread version of Filter Graph Manager
  • initialize and complete the filter schedule in a dedicated thread, which sends window messages while the schedule is running

That is, use the STA and additional threads by touching pointers, or else do not use the STA.

+3
source

After playing with IGlobalInterface and thinking about a Roman comment, I realized that setting up the function that handles samplegrabber is best in a different thread, bypassing the STA.

0
source

Source: https://habr.com/ru/post/1487940/


All Articles