Étape 6. Ajouter la prise en charge de COM

[La fonctionnalité associée à cette page, DirectShow, est une fonctionnalité héritée. Il a été remplacé par MediaPlayer, IMFMediaEngine et Audio/Video Capture in Media Foundation. Ces fonctionnalités ont été optimisées pour Windows 10 et Windows 11. Microsoft recommande vivement que le nouveau code utilise MediaPlayer, IMFMediaEngine et Audio/Video Capture dans Media Foundation au lieu de DirectShow, si possible. Microsoft suggère que le code existant qui utilise les API héritées soit réécrit pour utiliser les nouvelles API si possible.]

Il s’agit de l’étape 6 du didacticiel Écriture de filtres de transformation.

La dernière étape consiste à ajouter la prise en charge de COM.

Décompte de références

Vous n’avez pas besoin d’implémenter IUnknown::AddRef ou IUnknown::Release. Toutes les classes de filtre et d’épingle dérivent de CUnknown, qui gère le comptage des références.

QueryInterface

Toutes les classes de filtre et d’épingle implémentent IUnknown::QueryInterface pour toutes les interfaces COM dont elles héritent. Par exemple, CTransformFilter hérite d’IBaseFilter (via CBaseFilter). Si votre filtre n’expose pas d’interfaces supplémentaires, vous n’avez rien à faire d’autre.

Pour exposer des interfaces supplémentaires, remplacez la méthode CUnknown::NonDelegatingQueryInterface . Par exemple, supposons que votre filtre implémente une interface personnalisée nommée IMyCustomInterface. Pour exposer cette interface aux clients, procédez comme suit :

  • Dérivez votre classe de filtre de cette interface.
  • Placez la macro DECLARE_IUNKNOWN dans la section déclaration publique.
  • Remplacez NonDelegatingQueryInterface par case activée pour l’IID de votre interface et retournez un pointeur vers votre filtre.

Le code suivant illustre ces étapes :

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

Pour plus d’informations, consultez Comment implémenter IUnknown.

Création d’objets

Si vous envisagez d’empaqueter votre filtre dans une DLL et de le mettre à la disposition d’autres clients, vous devez prendre en charge CoCreateInstance et d’autres fonctions COM associées. La bibliothèque de classes de base implémente la plupart de ces ressources ; il vous suffit de fournir des informations sur votre filtre. Cette section donne une brève vue d’ensemble de ce qu’il faut faire. Pour plus d’informations, consultez Création d’une DLL de filtre DirectShow.

Tout d’abord, écrivez une méthode de classe statique qui retourne une nouvelle instance de votre filtre. Vous pouvez nommer cette méthode comme vous le souhaitez, mais la signature doit correspondre à celle indiquée dans l’exemple suivant :

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

Ensuite, déclarez un tableau global d’instances de classe CFactoryTemplate , nommé g_Templates. Chaque classe CFactoryTemplate contient des informations de Registre pour un filtre. Plusieurs filtres peuvent résider dans une seule DLL ; incluez simplement des entrées CFactoryTemplate supplémentaires. Vous pouvez également déclarer d’autres objets COM, tels que des pages de propriétés.

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

Définissez un entier global nommé g_cTemplates dont la valeur est égale à la longueur du tableau g_Templates :

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

Enfin, implémentez les fonctions d’inscription de DLL. L’exemple suivant montre l’implémentation minimale pour ces fonctions :

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

Filtrer les entrées de Registre

Les exemples précédents montrent comment inscrire le CLSID d’un filtre pour COM. Pour de nombreux filtres, cela suffit. Le client doit ensuite créer le filtre à l’aide de CoCreateInstance et l’ajouter au graphique de filtre en appelant IFilterGraph::AddFilter. Toutefois, dans certains cas, vous souhaiterez peut-être fournir des informations supplémentaires sur le filtre dans le Registre. Ces informations effectuent les opérations suivantes :

  • Permet aux clients de découvrir le filtre à l’aide du mappeur de filtre ou de l’énumérateur de périphérique système.
  • Permet au Gestionnaire de graphe de filtres de découvrir le filtre lors de la génération automatique du graphe.

L’exemple suivant inscrit le filtre d’encodeur RLE dans la catégorie du compresseur vidéo. Pour plus d’informations, consultez Comment inscrire des filtres DirectShow. Veillez à lire la section Instructions pour l’inscription des filtres, qui décrit les pratiques recommandées pour l’inscription des filtres.

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

En outre, les filtres n’ont pas besoin d’être empaquetés à l’intérieur des DLL. Dans certains cas, vous pouvez écrire un filtre spécialisé conçu uniquement pour une application spécifique. Dans ce cas, vous pouvez compiler la classe de filtre directement dans votre application et la créer avec l’opérateur new , comme illustré dans l’exemple suivant :

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

Connexion intelligente

Écriture de filtres DirectShow

Écriture de filtres de transformation