Etapa 6. Adicionar suporte para COM

[O recurso associado a esta página, DirectShow, é um recurso herdado. Ele foi substituído por MediaPlayer, IMFMediaEngine e Captura de Áudio/Vídeo na Media Foundation. Esses recursos foram otimizados para Windows 10 e Windows 11. A Microsoft recomenda fortemente que o novo código use MediaPlayer, IMFMediaEngine e Captura de Áudio/Vídeo no Media Foundation em vez de DirectShow, quando possível. A Microsoft sugere que o código existente que usa as APIs herdadas seja reescrito para usar as novas APIs, se possível.]

Esta é a etapa 6 do tutorial Escrevendo Filtros de Transformação.

A etapa final é adicionar suporte para COM.

Contagem de referências

Você não precisa implementar IUnknown::AddRef ou IUnknown::Release. Todas as classes de filtro e pino derivam de CUnknown, que manipula a contagem de referências.

QueryInterface

Todas as classes de filtro e pin implementam IUnknown::QueryInterface para todas as interfaces COM herdadas. Por exemplo, CTransformFilter herda IBaseFilter (por meio de CBaseFilter). Se o filtro não expor interfaces adicionais, você não precisará fazer mais nada.

Para expor interfaces adicionais, substitua o método CUnknown::NonDelegatingQueryInterface . Por exemplo, suponha que o filtro implemente uma interface personalizada chamada IMyCustomInterface. Para expor essa interface aos clientes, faça o seguinte:

  • Derive sua classe de filtro dessa interface.
  • Coloque a macro DECLARE_IUNKNOWN na seção declaração pública.
  • Substitua NonDelegatingQueryInterface para marcar para o IID da interface e retorne um ponteiro para o filtro.

O código a seguir mostra essas etapas:

CMyFilter : public CBaseFilter, public IMyCustomInterface
{
public:
    DECLARE_IUNKNOWN
    STDMETHODIMP NonDelegatingQueryInterface(REFIID iid, void **ppv);
};
STDMETHODIMP CMyFilter::NonDelegatingQueryInterface(REFIID iid, void **ppv)
{
    if (riid == IID_IMyCustomInterface) {
        return GetInterface(static_cast<IMyCustomInterface*>(this), ppv);
    }
    return CBaseFilter::NonDelegatingQueryInterface(riid,ppv);
}

Para obter mais informações, confira Como implementar o IUnknown.

Criação de objetos

Se você planeja empacotar seu filtro em uma DLL e disponibilizá-lo para outros clientes, você deve dar suporte a CoCreateInstance e outras funções COM relacionadas. A biblioteca de classes base implementa a maior parte disso; você só precisa fornecer algumas informações sobre seu filtro. Esta seção fornece uma breve visão geral do que fazer. Para obter detalhes, confira Como criar uma DLL de filtro DirectShow.

Primeiro, escreva um método de classe estática que retorna uma nova instância do filtro. Você pode nomear esse método como quiser, mas a assinatura deve corresponder à mostrada no exemplo a seguir:

CUnknown * WINAPI CRleFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr)
{
    CRleFilter *pFilter = new CRleFilter();
    if (pFilter== NULL) 
    {
        *pHr = E_OUTOFMEMORY;
    }
    return pFilter;
}

Em seguida, declare uma matriz global de instâncias de classe CFactoryTemplate , chamada g_Templates. Cada classe CFactoryTemplate contém informações de registro para um filtro. Vários filtros podem residir em uma única DLL; simplesmente inclua entradas CFactoryTemplate adicionais. Você também pode declarar outros objetos COM, como páginas de propriedades.

static WCHAR g_wszName[] = L"My RLE Encoder";
CFactoryTemplate g_Templates[] = 
{
  { 
    g_wszName,
    &CLSID_RLEFilter,
    CRleFilter::CreateInstance,
    NULL,
    NULL
  }
};

Defina um inteiro global chamado g_cTemplates cujo valor é igual ao comprimento da matriz de g_Templates :

int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);  

Por fim, implemente as funções de registro de DLL. O exemplo a seguir mostra a implementação mínima para essas funções:

STDAPI DllRegisterServer()
{
    return AMovieDllRegisterServer2( TRUE );
}
STDAPI DllUnregisterServer()
{
    return AMovieDllRegisterServer2( FALSE );
}

Filtrar Entradas do Registro

Os exemplos anteriores mostram como registrar o CLSID de um filtro para COM. Para muitos filtros, isso é suficiente. Em seguida, espera-se que o cliente crie o filtro usando CoCreateInstance e adicione-o ao grafo de filtro chamando IFilterGraph::AddFilter. Em alguns casos, no entanto, talvez você queira fornecer informações adicionais sobre o filtro no registro. Essas informações fazem o seguinte:

O exemplo a seguir registra o filtro de codificador RLE na categoria de compressor de vídeo. Para obter detalhes, confira Como registrar filtros do DirectShow. Leia a seção Diretrizes para Registrar Filtros, que descreve as práticas recomendadas para registro de filtro.

// Declare media type information.
FOURCCMap fccMap = FCC('MRLE'); 
REGPINTYPES sudInputTypes = { &MEDIATYPE_Video, &GUID_NULL };
REGPINTYPES sudOutputTypes = { &MEDIATYPE_Video, (GUID*)&fccMap };

// Declare pin information.
REGFILTERPINS sudPinReg[] = {
    // Input pin.
    { 0, FALSE, // Rendered?
         FALSE, // Output?
         FALSE, // Zero?
         FALSE, // Many?
         0, 0, 
         1, &sudInputTypes  // Media types.
    },
    // Output pin.
    { 0, FALSE, // Rendered?
         TRUE, // Output?
         FALSE, // Zero?
         FALSE, // Many?
         0, 0, 
         1, &sudOutputTypes      // Media types.
    }
};
 
// Declare filter information.
REGFILTER2 rf2FilterReg = {
    1,                // Version number.
    MERIT_DO_NOT_USE, // Merit.
    2,                // Number of pins.
    sudPinReg         // Pointer to pin information.
};

STDAPI DllRegisterServer(void)
{
    HRESULT hr = AMovieDllRegisterServer2(TRUE);
    if (FAILED(hr))
    {
        return hr;
    }
    IFilterMapper2 *pFM2 = NULL;
    hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
            IID_IFilterMapper2, (void **)&pFM2);
    if (SUCCEEDED(hr))
    {
        hr = pFM2->RegisterFilter(
            CLSID_RLEFilter,                // Filter CLSID. 
            g_wszName,                       // Filter name.
            NULL,                            // Device moniker. 
            &CLSID_VideoCompressorCategory,  // Video compressor category.
            g_wszName,                       // Instance data.
            &rf2FilterReg                    // Filter information.
            );
        pFM2->Release();
    }
    return hr;
}

STDAPI DllUnregisterServer()
{
    HRESULT hr = AMovieDllRegisterServer2(FALSE);
    if (FAILED(hr))
    {
        return hr;
    }
    IFilterMapper2 *pFM2 = NULL;
    hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
            IID_IFilterMapper2, (void **)&pFM2);
    if (SUCCEEDED(hr))
    {
        hr = pFM2->UnregisterFilter(&CLSID_VideoCompressorCategory, 
            g_wszName, CLSID_RLEFilter);
        pFM2->Release();
    }
    return hr;
}

Além disso, os filtros não precisam ser empacotados dentro de DLLs. Em alguns casos, você pode escrever um filtro especializado projetado apenas para um aplicativo específico. Nesse caso, você pode compilar a classe de filtro diretamente em seu aplicativo e criá-la com o new operador , conforme mostrado no exemplo a seguir:

#include "MyFilter.h"  // Header file that declares the filter class.
// Compile and link MyFilter.cpp.
int main()
{
    IBaseFilter *pFilter = 0;
    {
        // Scope to hide pF.
        CMyFilter* pF = new MyFilter();
        if (!pF)
        {
            printf("Could not create MyFilter.\n");
            return 1;
        }
        pF->QueryInterface(IID_IBaseFilter, 
            reinterpret_cast<void**>(&pFilter));
    }
    
    /* Now use pFilter as normal. */
    
    pFilter->Release();  // Deletes the filter.
    return 0;
}

Conexão Inteligente

Escrevendo filtros do DirectShow

Escrevendo filtros de transformação