Microsoft DirectX 8.1 (C++)

About Effect Filters

In Microsoft DirectShow, effect filters are defined as filters that apply an effect to media data, but don't change the media type.

Because the input and output media formats are the same, and the applied effect can't change the format, effect filters often contain a code that checks the media formatting. If the filter derives from one of the transform filter base classes, CTransformFilter or CTransInPlaceFilter, the filter typically checks the format with the CheckMediaType, CTransformFilter::CheckInputType, and CheckTransform methods. If the filter doesn't derive from one of the transform filter base classes, its pins typically check the format by calling the CBasePin::CheckMediaType member function.

You should choose a base class for your effect filter class that provides the greatest amount of the functionality you need. Often, the base class will be one of the transform filter base classes. If none of the higher-level base classes support your required functionality, you can choose CBaseFilter or CBasePin as your base class.

Your effect filter must implement the IPersistStream interface if you want to save the state of your effects in GraphEdit. To access this interface, derive your effect filter class from CPersistStream and query for the IPersistStream interface. Saving the filter's state can be helpful during design, but it is often useful to have the effect filter return to a default state when GraphEdit closes it, in which case you don't need to implement IPersistStream.

If you want the user to be able to manipulate the effect, you must create and display your effect filter's property page and provide a mechanism for returning the user's input to the filter. To do this, implement a property page class, the ISpecifyPropertyPages interface (which exposes property pages), and a custom interface that changes property page values. Typically, property pages use controls such as a slider, button, or check box to receive user input. You also must provide the resource file that displays the controls on the property page.

To implement the property page class, create a class that derives from CBasePropertyPage and implement the OnReceiveMessage method, the CPersistStream::SetDirty method, and a data member for each effect parameter. To access the two interfaces, derive your effect filter class from ISpecifyPropertyPages and the custom interface, and then query for the interfaces. You can query for all the interfaces you need by overriding the NonDelegatingQueryInterface method as shown in the following code example (IGargle is the custom interface):

STDMETHODIMP CGargle::NonDelegatingQueryInterface(REFIID riid, void **ppv)
{
    CheckPointer(ppv,E_POINTER);
    if (riid == IID_IGargle) {
        return GetInterface((IGargle *) this, ppv);
    } else if (riid == IID_ISpecifyPropertyPages) {
        return GetInterface((ISpecifyPropertyPages *) this, ppv);
    } else if (riid == IID_IPersistStream) {
        return GetInterface((IPersistStream *) this, ppv);
    } else {
        return CTransInPlaceFilter::NonDelegatingQueryInterface(riid, ppv);
    }
} 

The effect filter's custom interface typically supplies a put and a get method for each effect parameter. For example, the IGargle custom interface supplies put_GargleRate and get_GargleRate methods. The IContrast custom interface in the Contrast sample supplies put_ContrastLevel and get_ContrastLevel methods. When the user accesses one of the controls on the property page, the page generates a windows message. The property page class's OnReceiveMessage member function handles this message. The following code fragment from the Contrast sample demonstrates this message generation and handling. IDB_DEFAULT is the resource ID of the Default button. The user clicks this button to set the video contrast to its default state. The CContrastProperties class implements the property page and the IContrast::put_DefaultContrastLevel method sets the contrast level to its default value.

BOOL CContrastProperties::OnReceiveMessage(HWND hwnd, UINT uMsg, 
    WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
       case WM_COMMAND:
        {
          if (LOWORD(wParam) == IDB_DEFAULT)
            {
            pIContrast()->put_DefaultContrastLevel();
            SendMessage(m_hwndSlider, TBM_SETPOS, TRUE, 0L);
              SetDirty();
        }
            return (LRESULT) 1;
        }
...

Effect filters use critical sections internally to protect the global filter state. Effect filters can lock a critical section to ensure that data flow through the filter graph is serialized and that the global filter state doesn't change while an effect is occurring. DirectShow locks a critical section by declaring a CAutoLock class object. Typically, effect filters lock the critical section as soon as they enter the function that applies the effect. For example, in the following code fragment, the function that applies the effect is MessItAbout:

// Declare the critical section data member in 
// the effect filter class definition.
CCritSec   m_GargleLock; 

void CGargle::MessItAbout(PBYTE pb, int cb)
{
    CAutoLock foo(&m_GargleLock);

The put and get methods of the effect properties (for example, put_GargleRate) typically lock the critical section so effect values can't change in the middle of an update.