Paso 6. Agregar compatibilidad con COM

[La característica asociada a esta página, DirectShow, es una característica heredada. Se ha reemplazado por MediaPlayer, IMFMediaEngine y Captura de audio/vídeo en Media Foundation. Esas características se han optimizado para Windows 10 y Windows 11. Microsoft recomienda encarecidamente que el nuevo código use MediaPlayer, IMFMediaEngine y Audio/Video Capture en Media Foundation en lugar de DirectShow, siempre que sea posible. Microsoft sugiere que el código existente que usa las API heredadas se reescriba para usar las nuevas API si es posible.

Este es el paso 6 del tutorial Escritura de filtros de transformación.

El último paso es agregar compatibilidad con COM.

Recuento de referencias

No es necesario implementar IUnknown::AddRef o IUnknown::Release. Todas las clases de filtro y anclaje derivan de CUnknown, que controla el recuento de referencias.

QueryInterface

Todas las clases de filtro y anclaje implementan IUnknown::QueryInterface para las interfaces COM que heredan. Por ejemplo, CTransformFilter hereda IBaseFilter (a través de CBaseFilter). Si el filtro no expone ninguna interfaz adicional, no tiene que hacer nada más.

Para exponer interfaces adicionales, invalide el método CUnknown::NonDelegatingQueryInterface . Por ejemplo, supongamos que el filtro implementa una interfaz personalizada denominada IMyCustomInterface. Para exponer esta interfaz a los clientes, haga lo siguiente:

  • Derive la clase de filtro de esa interfaz.
  • Coloque la macro DECLARE_IUNKNOWN en la sección de declaración pública.
  • Invalide NonDelegatingQueryInterface para comprobar el IID de la interfaz y devolver un puntero al filtro.

El siguiente código muestra estos pasos:

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 obtener más información, vea Cómo implementar IUnknown.

Creación de objetos

Si tiene previsto empaquetar el filtro en un archivo DLL y ponerlo a disposición de otros clientes, debe admitir CoCreateInstance y otras funciones COM relacionadas. La biblioteca de clases base implementa la mayor parte de esto; solo tiene que proporcionar información sobre el filtro. En esta sección se proporciona una breve descripción de lo que se debe hacer. Para obtener más información, consulte How to Create a DirectShow Filter DLL(Cómo crear un archivo DLL de filtro directShow).

En primer lugar, escriba un método de clase estático que devuelva una nueva instancia del filtro. Puede asignar un nombre a este método como quiera, pero la firma debe coincidir con la que se muestra en el ejemplo siguiente:

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

A continuación, declare una matriz global de instancias de clase CFactoryTemplate , denominada g_Templates. Cada clase CFactoryTemplate contiene información del Registro para un filtro. Varios filtros pueden residir en un único archivo DLL; simplemente incluya entradas adicionales de CFactoryTemplate . También puede declarar otros objetos COM, como páginas de propiedades.

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

Defina un entero global denominado g_cTemplates cuyo valor sea igual a la longitud de la matriz g_Templates :

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

Por último, implemente las funciones de registro de DLL. En el ejemplo siguiente se muestra la implementación mínima para estas funciones:

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

Filtrar entradas del Registro

En los ejemplos anteriores se muestra cómo registrar el CLSID de un filtro para COM. Para muchos filtros, esto es suficiente. A continuación, se espera que el cliente cree el filtro mediante CoCreateInstance y agréguelo al grafo de filtro llamando a IFilterGraph::AddFilter. Sin embargo, en algunos casos, es posible que desee proporcionar información adicional sobre el filtro en el registro. Esta información hace lo siguiente:

En el ejemplo siguiente se registra el filtro de codificador RLE en la categoría de compresor de vídeo. Para obtener más información, consulte Cómo registrar filtros directShow. Asegúrese de leer la sección Directrices para registrar filtros, que describe los procedimientos recomendados para el registro de filtros.

// 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;
}

Además, los filtros no tienen que empaquetarse dentro de archivos DLL. En algunos casos, puede escribir un filtro especializado diseñado solo para una aplicación específica. En ese caso, puede compilar la clase de filtro directamente en la aplicación y crearla con el new operador , como se muestra en el ejemplo siguiente:

#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;
}

Conexión inteligente

Escribir filtros directShow

Escribir filtros de transformación