Share via


Media Foundation und COM

Microsoft Media Foundation verwendet eine Mischung aus COM-Konstrukten, ist aber keine vollständig COM-basierte API. In diesem Thema wird die Interaktion zwischen COM und Media Foundation beschrieben. Außerdem werden einige bewährte Methoden für die Entwicklung von Media Foundation-Plug-In-Komponenten definiert. Wenn Sie diese Methoden befolgen, können Sie einige häufige, aber subtile Programmierfehler vermeiden.

Bewährte Methoden für Anwendungen

In Media Foundation werden asynchrone Verarbeitung und Rückrufe von Arbeitswarteschlangen verarbeitet. Arbeitswarteschlangen verfügen immer über MTA-Threads (Multithreaded Apartment), sodass eine Anwendung eine einfachere Implementierung hat, wenn sie auch in einem MTA-Thread ausgeführt wird. Daher wird empfohlen, CoInitializeEx mit dem flag COINIT_MULTITHREADED aufzurufen.

Media Foundation marshallt keine STA-Objekte (Singlethreaded Apartment) in Arbeitswarteschlangenthreads. Außerdem wird sichergestellt, dass STA-Invarianten beibehalten werden. Daher muss eine STA-Anwendung darauf achten, keine STA-Objekte oder Proxys an Media Foundation-APIs zu übergeben. Objekte, die sta-only sind, werden in Media Foundation nicht unterstützt.

Wenn Sie über einen STA-Proxy für ein MTA- oder Freethread-Objekt verfügen, kann das Objekt mithilfe eines Arbeitswarteschlangenrückrufs in einen MTA-Proxy gemarshallt werden. Die CoCreateInstance-Funktion kann abhängig vom objektmodell, das in der Registrierung für diese CLSID definiert ist, entweder einen unformatierten Zeiger oder einen STA-Proxy zurückgeben. Wenn ein STA-Proxy zurückgegeben wird, dürfen Sie den Zeiger nicht an eine Media Foundation-API übergeben.

Angenommen, Sie möchten einen IPropertyStore-Zeiger an die IMFSourceResolver::BeginCreateObjectFromURL-Methode übergeben. Sie können PSCreateMemoryPropertyStore aufrufen, um den IPropertyStore-Zeiger zu erstellen. Wenn Sie aus einer STA aufrufen, müssen Sie den Zeiger marshallen, bevor Sie ihn an BeginCreateObjectFromURL übergeben.

Der folgende Code zeigt, wie Sie einen STA-Proxy in eine Media Foundation-API marshallen.

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

Weitere Informationen zur globalen Schnittstellentabelle finden Sie unter IGlobalInterfaceTable.

Wenn Sie Media Foundation prozessintern verwenden, sind objekte, die von Media Foundation-Methoden und -Funktionen zurückgegeben werden, direkte Zeiger auf das -Objekt. Für prozessübergreifende Media Foundation können diese Objekte MTA-Proxys sein und bei Bedarf in einen STA-Thread gemarshallt werden. Ebenso sind Objekte, die in einem Rückruf abgerufen werden – z. B. eine Topologie aus dem MESessionTopologyStatus-Ereignis – direkte Zeiger, wenn Media Foundation prozessintern verwendet wird, aber MTA-Proxys, wenn Media Foundation prozessübergreifend verwendet wird.

Hinweis

Das gängigste Szenario für die prozessübergreifende Verwendung von Media Foundation ist der geschützte Medienpfad (Protected Media Path , PMP). Diese Hinweise gelten jedoch für alle Situationen, in denen Media Foundation-APIs über RPC verwendet werden.

 

Alle Implementierungen von IMFAsyncCallback sollten MTA-kompatibel sein. Diese Objekte müssen überhaupt keine COM-Objekte sein. Wenn sie dies sind, können sie jedoch nicht in der STA ausgeführt werden. Die IMFAsyncCallback::Invoke-Funktion wird in einem MTA-Arbeitsqueuethread aufgerufen, und das bereitgestellte IMFAsyncResult-Objekt ist entweder ein direkter Objektzeiger oder ein MTA-Proxy.

Bewährte Methoden für Media Foundation-Komponenten

Es gibt zwei Kategorien von Media Foundation-Objekten, die sich um COM kümmern müssen. Einige Komponenten, z. B. Transformationen oder Bytestreamhandler, sind vollständige COM-Objekte, die von CLSID erstellt werden. Diese Objekte müssen den Regeln für COM-Apartments entsprechen, sowohl für prozessinterne als auch für prozessübergreifende Media Foundation. Andere Media Foundation-Komponenten sind keine vollständigen COM-Objekte, benötigen jedoch COM-Proxys für die prozessübergreifende Wiedergabe. Zu den Objekten in dieser Kategorie gehören Medienquellen und Aktivierungsobjekte. Diese Objekte können Apartmentprobleme ignorieren, wenn sie nur für in-Process Media Foundation verwendet werden.

Obwohl nicht alle Media Foundation-Objekte COM-Objekte sind, werden alle Media Foundation-Schnittstellen von IUnknown abgeleitet. Daher müssen alle Media Foundation-Objekte IUnknown gemäß den COM-Spezifikationen implementieren, einschließlich der Regeln für die Verweiszählung und QueryInterface. Alle referenzgezählten Objekte sollten auch sicherstellen, dass DllCanUnloadNow das Entladen des Moduls nicht zulässt, während die Objekte weiterhin bestehen bleiben.

Media Foundation-Komponenten dürfen keine STA-Objekte sein. Viele Media Foundation-Objekte müssen überhaupt keine COM-Objekte sein. Wenn sie dies sind, können sie jedoch nicht in der STA ausgeführt werden. Alle Media Foundation-Komponenten müssen threadsicher sein. Einige Media Foundation-Objekte müssen auch freithread- oder apartmentneutral sein. In der folgenden Tabelle sind die Anforderungen für implementierungen benutzerdefinierte Schnittstellen angegeben:

Schnittstelle Category Erforderliche Wohnung
IMFAktivieren Prozessübergreifender Proxy Freithread oder neutral
IMFByteStreamHandler COM-Objekt MTA
IMFContentProtectionManager Prozessübergreifender Proxy Freithread oder neutral
IMFQualityManager COM-Objekt Freithread oder neutral
IMFMediaSource Prozessübergreifender Proxy Freithread oder neutral
IMFSchemeHandler COM-Objekt MTA
IMFTopoLoader COM-Objekt Freithread oder neutral
IMFTransform COM-Objekt MTA

 

Abhängig von der Implementierung können zusätzliche Anforderungen bestehen. Wenn beispielsweise eine Mediensenke eine andere Schnittstelle implementiert, die es der Anwendung ermöglicht, direkte Funktionsaufrufe an die Senke zu tätigen, müsste die Senke freethreaded oder neutral sein, damit sie direkte prozessübergreifende Aufrufe verarbeiten kann. Jedes Objekt kann Freithreads sein; In dieser Tabelle sind die Mindestanforderungen angegeben.

Die empfohlene Möglichkeit zum Implementieren von Freethread-Objekten oder neutralen Objekten besteht darin, den Freethread-Marshaller zu aggregieren. Weitere Informationen finden Sie in der MSDN-Dokumentation zu CoCreateFreeThreadedMarshaler. In Übereinstimmung mit der Anforderung, STA-Objekte oder Proxys nicht an Media Foundation-APIs zu übergeben, müssen sich Freethreadobjekte keine Gedanken über das Marshallen von STA-Eingabezeigern in Freethread-Komponenten machen.

Komponenten, die die Lange Funktionsarbeitswarteschlange (MFASYNC_CALLBACK_QUEUE_LONG_FUNCTION) verwenden, müssen mehr Sorgfalt walten lassen. Threads in der Workqueue der langen Funktion erstellen eine eigene STA. Komponenten, die die Lange Funktions-Workqueue für Rückrufe verwenden, sollten das Erstellen von COM-Objekten in diesen Threads vermeiden und bei Bedarf Proxys an die STA marshallen.

Zusammenfassung

Anwendungen haben eine einfachere Zeit, wenn sie über einen MTA-Thread mit Media Foundation interagieren, aber es ist mit einiger Sorgfalt möglich, Media Foundation aus einem STA-Thread zu verwenden. Media Foundation verarbeitet keine STA-Komponenten, und Anwendungen sollten darauf achten, sta-Objekte nicht an Media Foundation-APIs zu übergeben. Einige Objekte haben zusätzliche Anforderungen, insbesondere Objekte, die in einer prozessübergreifenden Situation ausgeführt werden. Wenn Sie diese Richtlinien befolgen, können Sie COM-Fehler, Deadlocks und unerwartete Verzögerungen bei der Medienverarbeitung vermeiden.

Media Foundation Platform-APIs

Media Foundation-Architektur