Share via


Media Foundation et COM

Microsoft Media Foundation utilise une combinaison de constructions COM, mais n’est pas une API entièrement basée sur COM. Cette rubrique décrit l’interaction entre COM et Media Foundation. Il définit également certaines bonnes pratiques pour le développement de composants de plug-in Media Foundation. Suivre ces pratiques peut vous aider à éviter certaines erreurs de programmation courantes mais subtiles.

Meilleures pratiques pour les applications

Dans Media Foundation, le traitement asynchrone et les rappels sont gérés par des files d’attente de travail. Les files d’attente de travail ont toujours des threads d’appartement multithread (MTA), de sorte qu’une application aura une implémentation plus simple si elle s’exécute également sur un thread MTA. Par conséquent, il est recommandé d’appeler CoInitializeEx avec l’indicateur COINIT_MULTITHREADED .

Media Foundation ne marshale pas les objets STA (Single-Threaded Apartment) pour les threads de file d’attente de travail. Elle ne garantit pas non plus que les invariants STA soient maintenus. Par conséquent, une application STA doit veiller à ne pas passer d’objets OU de proxys STA aux API Media Foundation. Les objets STA uniquement ne sont pas pris en charge dans Media Foundation.

Si vous disposez d’un proxy STA vers un objet MTA ou avec thread libre, l’objet peut être marshalé vers un proxy MTA à l’aide d’un rappel de file d’attente de travail. La fonction CoCreateInstance peut retourner un pointeur brut ou un proxy STA, en fonction du modèle objet défini dans le Registre pour ce CLSID. Si un proxy STA est retourné, vous ne devez pas passer le pointeur vers une API Media Foundation.

Par exemple, supposons que vous souhaitiez passer un pointeur IPropertyStore à la méthode IMFSourceResolver::BeginCreateObjectFromURL . Vous pouvez appeler PSCreateMemoryPropertyStore pour créer le pointeur IPropertyStore . Si vous appelez à partir d’un STA, vous devez marshaler le pointeur avant de le passer à BeginCreateObjectFromURL.

Le code suivant montre comment marshaler un proxy STA vers une API Media Foundation.

class CCreateSourceMarshalCallback
    : public IMFAsyncCallback
{
public:
    CCreateSourceMarshalCallback(
        LPCWSTR szURL, 
        IMFSourceResolver* pResolver, 
        IPropertyStore* pSourceProps, 
        IMFAsyncCallback* pCompletionCallback, 
        HRESULT& hr
        )
        : m_szURL(szURL), 
          m_pResolver(pResolver), 
          m_pCompletionCallback(pCompletionCallback),
          m_pGIT(NULL),
          m_cRef(1)
    {
        hr = CoCreateInstance(CLSID_StdGlobalInterfaceTable, NULL, 
            CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_pGIT));

        if(SUCCEEDED(hr))
        {
            hr = m_pGIT->RegisterInterfaceInGlobal(
                pSourceProps, IID_IPropertyStore, &m_dwInterfaceCookie);
        }
    }
    ~CCreateSourceMarshalCallback()
    {
        SafeRelease(&m_pResolver);
        SafeRelease(&m_pCompletionCallback);
        SafeRelease(&m_pGIT);
    }


    STDMETHOD_(ULONG, AddRef)()
    {
        return InterlockedIncrement(&m_cRef);
    }

    STDMETHOD_(ULONG, Release)()
    {
        LONG cRef = InterlockedDecrement(&m_cRef);
        if (0 == cRef)
        {
            delete this;
        }
        return cRef;
    }

    STDMETHOD(QueryInterface)(REFIID riid, LPVOID* ppvObject)
    {
        static const QITAB qit[] = 
        {
            QITABENT(CCreateSourceMarshalCallback, IMFAsyncCallback),
            { 0 }
        };
        return QISearch(this, qit, riid, ppvObject);

    }

    STDMETHOD(GetParameters)(DWORD* pdwFlags, DWORD* pdwQueue)
    {
        return E_NOTIMPL;
    }

    STDMETHOD(Invoke)(IMFAsyncResult* pResult)
    {
        IPropertyStore *pSourceProps = NULL;

        HRESULT hr = m_pGIT->GetInterfaceFromGlobal(
            m_dwInterfaceCookie, 
            IID_PPV_ARGS(&pSourceProps)
            );

        if(SUCCEEDED(hr))
        {
            hr = m_pResolver->BeginCreateObjectFromURL(
                m_szURL, MF_RESOLUTION_MEDIASOURCE, pSourceProps, NULL, 
                m_pCompletionCallback, NULL);
        }

        SafeRelease(&pSourceProps);
        return hr;
    }

private:
    LPCWSTR m_szURL;
    IMFSourceResolver *m_pResolver;
    IMFAsyncCallback *m_pCompletionCallback;
    IGlobalInterfaceTable *m_pGIT;
    DWORD m_dwInterfaceCookie;
    LONG m_cRef;
};

Pour plus d’informations sur la table d’interface globale, consultez IGlobalInterfaceTable.

Si vous utilisez Media Foundation in-process, les objets retournés par les méthodes et fonctions Media Foundation sont des pointeurs directs vers l’objet. Pour Media Foundation inter-processus, ces objets peuvent être des proxys MTA et doivent être marshalés dans un thread STA si nécessaire. De même, les objets obtenus à l’intérieur d’un rappel (par exemple, une topologie à partir de l’événement MESessionTopologyStatus ) sont des pointeurs directs lorsque Media Foundation est utilisé dans le processus, mais sont des proxys MTA lorsque Media Foundation est utilisé entre processus.

Notes

Le scénario le plus courant pour l’utilisation croisée de Media Foundation est avec le chemin d’accès multimédia protégé (PMP). Toutefois, ces remarques s’appliquent à n’importe quelle situation où les API Media Foundation sont utilisées via RPC.

 

Toutes les implémentations d’IMFAsyncCallback doivent être compatibles avec MTA. Ces objets n’ont pas besoin d’être des objets COM du tout. Mais s’ils le sont, ils ne peuvent pas s’exécuter dans le STA. La fonction IMFAsyncCallback::Invoke sera appelée sur un thread de file d’attente de travail MTA, et l’objet IMFAsyncResult fourni sera un pointeur d’objet direct ou un proxy MTA.

Meilleures pratiques pour les composants Media Foundation

Il existe deux catégories d’objets Media Foundation qui doivent se préoccuper de COM. Certains composants, tels que les transformations ou les gestionnaires de flux d’octets, sont des objets COM complets créés par CLSID. Ces objets doivent suivre les règles pour les appartements COM, à la fois pour Media Foundation in-process et inter-processus. Les autres composants Media Foundation ne sont pas des objets COM complets, mais ont besoin de proxys COM pour la lecture inter-processus. Les objets de cette catégorie incluent les sources multimédias et l’objet d’activation. Ces objets peuvent ignorer les problèmes d’appartement s’ils sont utilisés uniquement pour Media Foundation in-process.

Bien que tous les objets Media Foundation ne soient pas des objets COM, toutes les interfaces Media Foundation dérivent d’IUnknown. Par conséquent, tous les objets Media Foundation doivent implémenter IUnknown conformément aux spécifications COM, y compris les règles pour le comptage des références et QueryInterface. Tous les objets comptabilisés par référence doivent également garantir que DllCanUnloadNow n’autorisera pas le déchargement du module tant que les objets persistent.

Les composants Media Foundation ne peuvent pas être des objets STA. De nombreux objets Media Foundation n’ont pas besoin d’être des objets COM. Mais s’ils le sont, ils ne peuvent pas s’exécuter dans le STA. Tous les composants Media Foundation doivent être thread-safe. Certains objets Media Foundation doivent également être à thread libre ou neutres dans l’appartement. Le tableau suivant spécifie la configuration requise pour les implémentations d’interface personnalisées :

Interface Category Appartement requis
FMIActiver Proxy inter-processus Thread libre ou neutre
IMFByteStreamHandler Objet COM MTA
IMFContentProtectionManager Proxy inter-processus Thread libre ou neutre
IMFQualityManager Objet COM Thread libre ou neutre
IMFMediaSource Proxy inter-processus Thread libre ou neutre
IMFSchemeHandler Objet COM MTA
IMFTopoLoader Objet COM Thread libre ou neutre
IMFTransform Objet COM MTA

 

Il peut y avoir des exigences supplémentaires en fonction de l’implémentation. Par exemple, si un récepteur multimédia implémente une autre interface qui permet à l’application d’effectuer des appels de fonction directs au récepteur, le récepteur doit être à thread libre ou neutre, afin de pouvoir gérer les appels inter-processus directs. N’importe quel objet peut être en thread libre ; ce tableau spécifie la configuration minimale requise.

La méthode recommandée pour implémenter des objets libres ou neutres consiste à agréger le marshaler à threads libres. Pour plus d’informations, consultez la documentation MSDN sur CoCreateFreeThreadedMarshaler. Conformément à l’exigence de ne pas passer d’objets STA ou de proxys aux API Media Foundation, les objets à thread libre n’ont pas besoin de se soucier du marshaling des pointeurs d’entrée STA dans des composants à thread libre.

Les composants qui utilisent la file d’attente de travail à fonction longue (MFASYNC_CALLBACK_QUEUE_LONG_FUNCTION) doivent être plus prudents. Les threads de la longue file d’attente de fonction créent leur propre STA. Les composants qui utilisent la longue file d’attente de fonction pour les rappels doivent éviter de créer des objets COM sur ces threads et doivent veiller à marshaler les proxys vers le STA si nécessaire.

Résumé

Les applications auront plus de facilité s’ils interagissent avec Media Foundation à partir d’un thread MTA, mais il est possible avec un certain soin d’utiliser Media Foundation à partir d’un thread STA. Media Foundation ne gère pas les composants STA et les applications doivent veiller à ne pas passer d’objets STA aux API Media Foundation. Certains objets ont des exigences supplémentaires, en particulier les objets qui s’exécutent dans une situation inter-processus. En suivant ces instructions, vous éviterez les erreurs COM, les interblocages et les retards inattendus dans le traitement multimédia.

API de plateforme Media Foundation

Architecture Media Foundation