Microsoft DirectX 8.1 (C++)

Filter Policies

This topic applies to Windows XP Home Edition and Windows XP Professional only.

A DirectShow filter can implement a policy. For example, it might do this if the policy needs to examine information in a stream. As described in the previous section, filter policies are dynamic. When the filter joins the filter graph, it adds the policy to the CA Manager. It removes the policy when it leaves the graph. Both steps happen during the filter’s IBaseFilter::JoinFilterGraph method.

When the filter is added to the graph, the JoinFilterGraph method receives an IFilterGraph pointer. Query the IFilterGraph pointer for the IServiceProvider interface. The CA Manager is registered as a service with the filter graph manager. Call the IServiceProvider::QueryService method to obtain the CA Manager’s ICAManager interface. Use this interface to add the policy to the policies collection.

When the filter is removed from the graph, the JoinFilterGraph method receives a NULL pointer. The filter should remove its policy from the CA Manager.

Note   A filter policy should not hold a reference count on the ICAManager pointer, because this leads to a circular reference count. Instead, store a non-referenced pointer and explicitly set it to NULL when the filter leaves the graph.

The following code example shows how a filter might add a policy. Error handling is omitted for clarity:

STDMETHODIMP CMyFilter::JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName)
{
    // Call the base class method.
    hr = CBaseFilter::JoinFilterGraph(pGraph, pName);
    if (pGraph == NULL) // Filter is leaving the graph.
    {
        return m_pPolicy->RemoveYourself();
    }
    else // Filter is joining the graph.
    {
        ICAManager *pCAManager;
        IServiceProvider *pProvider = NULL;
        // Get the CA Manager from the filter graph manager.
        hr = pGraph->QueryInterface(IID_IServiceProvider, 
                                    (void**)&pProvider)
        hr = pProvider->QueryService(SID_CAManager, IID_ICAManager,
                                     (void**)&pCAManager);
        hr = m_pPolicy->AddYourself(pCAManager);
        pCAManager->Release();
        pProvider->Release();
    }
    return hr;
}

The previous example assumes that the filter has a member variable, m_pPolicy, which points to the policy object. It also assumes that the policy object implements two helper methods, AddYourself and RemoveYourself. The following code example shows a possible implementation of the AddYourself method:

HRESULT CMyPolicy::AddYourself(ICAManager *pCAManager)
{
    if (pCAManager)
    {
        CComPtr<ICAPolicies> pPolicies;
        CComQIPtr<ICAPolicies> pPolicy(GetControllingUnknown());
        pCAManager->get_Policies(&pPolicies);
        pPolicies->Add(pPolicy);
        m_pCAManager = pCAManager;  // Not a smart pointer; no AddRef.
        m_fOkToRemove = FALSE;
    }
    return S_OK;
}

The policy passes a pointer to itself to the ICAPolicies::Add method. It also stores a non-referenced ICAManager pointer, and sets an internal flag that prevents the policy from being removed. The policy’s RemoveYourself method needs to reverse these steps:

HRESULT CMyPolicy::RemoveYourself()
{
    if (m_pCAManager)
    {
        CComPtr<ICAPolicies> pPolicies;
        CComQIPtr<IUnknown> pUnk(GetControllingUnknown());
        CComVariant cv(pUnk);
        m_fOkToRemove = TRUE;
        m_pCAManager->get_Policies(&pPolicies);
        pPolicies->Remove(cv);
        m_pCAManager = NULL;
    }
    return S_OK;
}

The policy’s get_OkToRemove method returns the value of the m_fOkToRemove flag:

STDMETHODIMP CMyPolicy::get_OkToRemove(BOOL *pfOkToRemove)
{
    if (pfOkToRemove == NULL)
        return E_POINTER;
    *pfOkToRemove = m_fOkToRemove;
    return S_OK;
}

It is important to set the m_fOkToRemove flag to TRUE before removing the policy. The policies collection calls the ICAPolicy::get_OkToRemove method to confirm that it has permission to remove a policy.

Kernel Filters

If you are writing a ring-0 hardware driver for a tuner card and want to support conditional access, you must create a BDA conditional access driver and a BDA conditional access KSProxy plug-in. The BDA conditional access driver must support several property sets, including KSEVENTSETID_BdaCAEvent, KSPROPSETID_BdaCA, KSPROPSETID_BdaDescriptor, KSPROPSETID_BdaPmtProcessor, and KSPROPSETID_BdaEsMap. For more information about these property sets, see the BDA DDK Reference. For general information on creating a BDA driver, see the BDA Minidrivers section of the DDK.