The problem is that DirectShow filters are early COM classes that implement a subset of COM in part of reference counting, interfaces, monikers, persistence - basically all good things lasted for years - however they ignore apartments completely. DirectShow is multithreaded on its own and it is typical that there is a controlling thread, and there are worker streaming threads aside. DirectShow concepts assume you can easily pass interface pointers between threads and no marshaling is involved, expected and required.
Then came .NET with checking COM wrappers, and DirectShow.NET wrapped interface pointers as if they were fully featured apartment-aware COM pointers. At the same time Microsoft stopped giving updates to DirectShow (such as for example supplying Sample Grabber with free threaded marshaler) and eventually you hit the issue when on .NET you cannot do a supposedly simple thing with the interface pointer.
There is still absolutely no problem working with APIs in native code domain because you can skip marshaling there and work with direct pointers.
You build the graph on one apartment, and then you get a call back from Sample Grabber on another apartment (or, otherwise, in your scenario you just do something on a worker thread). You cannot use original interface pointers, esp. those in member variables, because .NET runtime check would hit apartment mismatch, esp, trying to marshal interface pointer for another apartment.
If it were your custom filter with source code, you could have added a custom IMarshal
implementation or leverage free threaded marshaler to fix the .NET issue on native code side, or otherwise add a helper to pass pointers across apartments.
In .NET code domain the best approach would be to avoid working with pointers from multiple apartments. There possibly are choices, but the easiest one I think of off the top of my head is to
- work in MTA to be able to have multiple threads accessing DirectShow interface pointers
- use
CLSID_FilterGraphNoThread
version of Filter Graph Manager
- initialize and terminate filter graph on a dedicated thread, which during graph operation dispatches window messages
That is, either use STA and no extra threads touching pointers, or otherwise not use STA.