Search code examples
directshowdirectshow.net

Dynamically change filter value without Property Page


I just wrote a simple DirectShow Filter (which inherits from CTransformFilter).

But I want to be able to set a variable of my filter dynamically. 
This can be done today using Property Page. 
But what i want is change this property programatically. 

I defined a custom COM interface to set a variable in the filter but can not figure out how to use it -access it...

How to set a DirectShow filter's properties value without open the 
filter's property page ?

Any one has idea?

More Details:

Well

i) Firt i just defined simple interface

DEFINE_GUID(IID_IApplyFilterControl,  X, X, X, X, X, X, X, X, X, X, X);


interface IApplyFilterControl : public IUnknown
{
    STDMETHOD(SetWillApplyFilterX)(bool applyFilter) = 0;
};

ii) Then in my Filter C++ Code i implement this interface

class MyFilter : public CTransformFilter , public IApplyFilterControl 
{
    ....
    STDMETHODIMP SetWillApplyFilter(bool apply)
    {
        CAutoLock lock(&m_csShared);
        willApplyFilter = apply;
        return S_OK;

    }
    ...

}

iii) In my C# Code (using DirectShowNet)

I want to able to access my filter

IBaseFilter myFilter = 
(IBaseFilter)Activator.CreateInstance(Type.GetTypeFromCLSID(myFilterGuid));
....
IApplyFilterControl filterControl = (IApplyFilterControl ) myFilter;
.....

filterControl->SetWillApplyFilter(true)

Finally I Fix It

Take the advice of yms and use hints from the link : Some advices about custom filters

Source: http://social.msdn.microsoft.com/Forums/en-US/windowsdirectshowdevelopment/thread/e02aa741-776c-42cf-869f-640747e197e4

i) Your COM Interface

// The GUID that identifies your interface
// {13F23FD9-A90C-480d-A597-F46BA20070AC}

static const GUID IIDTransformFilterControl =

{
      0x13f23fd9, 0xa90c, 0x480d, { 0xa5, 0x97, 0xf4, 0x6b, 0xa2, 0x0, 0x70, 0xac }
};

DECLARE_INTERFACE_(ITransformFilterControl, IUnknown)

{
    STDMETHOD(setGreyscale)(bool enable) = 0;
};

ii) Your transform Filter

class YourTransformFilter : 
public CTransformFilter, public ITransformFilterControl

{
    public:
    STDMETHODIMP    NonDelegatingQueryInterface(REFIID riid, void **ppv);
    STDMETHODIMP    setGreyscale(bool enable);
};

....

STDMETHODIMP  YourTransformFilter::NonDelegatingQueryInterface(REFIID riid, void **ppv)

{
    CheckPointer(ppv, E_POINTER);

    if(riid==IIDTransformFilterControl)   
      return GetInterface((ITransformFilterControl*) this, ppv);

    return CTransformFilter::NonDelegatingQueryInterface(riid, ppv);
}

STDMETHODIMP  YourTransformFilter:: setGreyscale(bool enable)

{
    bGreyscale    = enable;
    return S_OK;
}

iii) Finally In your C# host application Define COM Interface

[ComImport, System.Security.SuppressUnmanagedCodeSecurity, 
Guid("13F23FD9-A90C-480d-A597-F46BA20070AC"), 
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]

public interface ITransformControl

{
        [PreserveSig]
        int setGreyscale(bool enable);
}

iv) And Use in your C# code

ITransformFilterControl transformControl = 
     yourFilterInstance as ITransformFilterControl;

if(transformControl!=null)

{
    transformControl->setGreyscale(true);
}

Solution

  • If you defined a COM interface to access your filter, all you need to do now is to declare the same interface (using the same GUIs) in C#/VB.Net or whatever .net language you are using. Then you can do a type cast of your filter to the new interface. Here is a C# example on how to declare such an interface:

    using System.Runtime.InteropServices;
    
    // Declare IMediaControl as a COM interface which 
    // derives from the IDispatch interface. 
    [Guid("56A868B1-0AD4-11CE-B03A-0020AF0BA770"),
        InterfaceType(ComInterfaceType.InterfaceIsDual)] 
    interface IMediaControl // cannot list any base interfaces here 
    { 
        // Note that the members of IUnknown and Interface are NOT
        // listed here 
        //
        void Run();
    
        void Pause();
    
        void Stop();
    
        void GetState( [In] int msTimeout, [Out] out int pfs);
    
        void RenderFile(
        [In, MarshalAs(UnmanagedType.BStr)] string strFilename);
    
        void AddSourceFilter(
        [In, MarshalAs(UnmanagedType.BStr)] string strFilename, 
        [Out, MarshalAs(UnmanagedType.Interface)] out object ppUnk);
    
        [return : MarshalAs(UnmanagedType.Interface)]
        object FilterCollection();
    
        [return : MarshalAs(UnmanagedType.Interface)]
        object RegFilterCollection();
    
        void StopWhenReady(); 
    }
    

    EDIT:

    About the issue with E_NOINTERFACE during casting, it looks like a threading problem. 1- Creating your filter with Activator is not a good idea, you should always allow your DS graph to create your filters, try using "enumarate filters" instead. 2- Verify that the treading model you are using for your filter is "Both".Read here and here for some more information.