Search code examples
c#comffmpegdirectshowcom-interop

Registration free (sxs) COM DirectShow filter


There are questions asking on how to get Registration free COM working, and this is not one of those. I have a DirectShow video source filter (catagory 860BB310-5D01-11d0-BD3B-00A0C911CE86) implemented in .Net with the help of an edited version of the code available here: Pure .Net DirectShow Filters by Maxim Kartavenkov.

I need to get ffmpeg to recognize my .Net DirectShow filter as a video source using Registration Free COM (Side by Side / sxs). Built into the .Net framework is support for COM component servers, so theoretically as long as the manifests are correct, ffmpeg should detect the filters.

Here is a snippet of the relevant sections of my manifest files currently.

<!-- FFMPEG MANIFEST -->
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<assemblyIdentity name="ffmpeg.exe" version="1.0.0.0" type="win32" processorArchitecture="*"/>
<dependency>
 <dependentAssembly asmv2:codebase="DShowVideoFilter.manifest">
  <assemblyIdentity name="DShowVideoFilter" version="1.0.0.0" publicKeyToken="26A05D7C90FBA3E8"/>
 </dependentAssembly>
</dependency>
</assembly>


<!-- DIRECTSHOW FILTER MANIFEST -->
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
   <assemblyIdentity name="DShowVideoFilter" version="1.0.0.0" publicKeyToken="26A05D7C90FBA3E8" />
   <clrClass
      clsid="{65722BE6-3449-4628-ABD3-74B6864F9739}"
      progid="DShowVideoFilter.VideoCaptureFilter"
      threadingModel="Both"
      runtimeVersion="v2.0.50727"/>
   <file name="DShowVideoFilter.dll">
   </file>
   <file name="DShowVideoFilter.tlb">
     <typelib
        tlbid="{B618E67B-64C8-48E9-9F94-F13214B76808}"
        version="1.0"
        helpdir=""
        flags="hasdiskimage"/>
   </file>
</assembly>

So, I get no errors when running ffmpeg (like you would if there was a manifest error) - and I am confident that everything that is configured correctly (related to traditional sxs com loading), the problem I think (unconfirmed) is that ffmpeg loads DShow filters via DirectShow's intelligent connect system, which requires the filter and pins to be registered. Here are some documents that talk about how filters need to be registered that I've found:

Now, in Maxim Kartavenkov's DShow base classes, he takes care of #2 automatically. Here is a significantly shortened version of the method that registers the filters implementing BaseFilter.

[ComRegisterFunction]
public static void RegisterFunction(Type _type)
{
    AMovieSetup _setup = (AMovieSetup)Attribute.GetCustomAttribute(_type, typeof(AMovieSetup));
    BaseFilter _filter = (BaseFilter)Activator.CreateInstance(_type);
    string _name = _filter.Name;
    DsGuid _category = new DsGuid(_setup.Category);
    IFilterMapper2 _mapper2 = (IFilterMapper2)new FilterMapper2();

    RegFilter2 _reg2 = new RegFilter2();
    _reg2.dwVersion = (int)_setup.Version;
    _reg2.dwMerit = _setup.FilterMerit;
    _reg2.rgPins = IntPtr.Zero;
    _reg2.cPins = 0;

    IntPtr _register = Marshal.AllocCoTaskMem(Marshal.SizeOf(_reg2));
    Marshal.StructureToPtr(_reg2, _register, true);

    hr = _mapper2.RegisterFilter(_type.GUID, _name, IntPtr.Zero, _category, _instance, _register);

    Marshal.FreeCoTaskMem(_register);
}

That is the method (particularly mapper2.RegisterFilter) that allows ffmpeg to find the DShow filter when it is registered traditionally (with RegAsm) into the registry, which creates registry keys for the filter and pins as described by #2 link.

tldr;
So the question is, how to emulate the function of RegisterFilter or the intelligent connect registry entries this within a manifest file as to allow the sxs context to find my DirectShow filter when ffmpeg searches for it.


Solution

  • This is almost one of those questions asking on how to get registration-free COM working.

    As you correctly say, it's not a problem with getting it to work at the most basic level. However, the fact that the manifest doesn't generate SxS loading errors only means it's a valid manifest XML. To know if it's semantically correct, such as finding missing dependencies or typos in names, CLSIDs and/or versions, test with CLSIDFromProgID followed by CoCreateInstance natively, or Type.GetTypeFromCLSID/Type.GetTypeFromProgID followed by Activator.CreateInstance in .NET.

    Unfortunately for cases like this, registration-free COM is only applicable for base COM functionality, like typical class, interface proxy/stub and type library registration, with a tiny bit of OLE (see miscStatus attributes). For categories or subkeys not used by COM itself, registration is necessary.

    Why? Because no one else followed lead, not even COM+.