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. Außerdem werden einige bewährte Methoden für die Entwicklung Media Foundation Plug-In-Komponenten definiert. Mithilfe dieser Vorgehensweisen können Sie einige häufige, aber kleine 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 (Multithread-Apartment), sodass eine Anwendung eine einfachere Implementierung hat, wenn sie auch in einem MTA-Thread ausgeführt wird. Daher wird empfohlen, CoInitializeEx mit dem COINIT _ MULTITHREADED-Flag auf aufruft.

Media Foundation marshallt keine Sta-Objekte (SingleThreaded Apartment) in Arbeitswarteschlangenthreads. Es wird auch nicht sichergestellt, dass STA-Invarianten beibehalten werden. Aus diesem Grund muss eine STA-Anwendung darauf achten, STA-Objekte oder Proxys nicht an Media Foundation-APIs zu übergeben. Objekte, die nur STA sind, werden in der Media Foundation.

Wenn Sie über einen STA-Proxy für ein MTA- oder Freethread-Objekt verfügen, kann das Objekt mithilfe eines Work-Queue-Rückrufs an einen MTA-Proxy gemarshallt werden. Die CoCreateInstance-Funktion kann je nach objektorientiertem Modell, das in der Registrierung für diese CLSID definiert ist, entweder einen rohen Zeiger oder einen STA-Proxy zurückgeben. Wenn ein STA-Proxy zurückgegeben wird, dürfen Sie den Zeiger nicht an eine Media Foundation übergeben.

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

Der folgende Code zeigt, wie sie einen STA-Proxy an eine Media Foundation 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 die Media Foundation in-Process verwenden, sind von Media Foundation Methoden und Funktionen zurückgegebene Objekte direkte Zeiger auf das Objekt. Bei prozessübergreifenden Media Foundation handelt es sich bei diesen Objekten möglicherweise um MTA-Proxys, die bei Bedarf in einen STA-Thread gemarshallt werden sollten. Ebenso sind Objekte, die innerhalb eines Rückrufs , z. B. eine Topologie aus dem MESessionTopologyStatus-Ereignis, direkte Zeiger sind, wenn Media Foundation prozessübergreifend verwendet wird, aber MTA-Proxys, wenn Media Foundation prozessübergreifend verwendet wird.

Hinweis

Das häufigste Szenario für die Verwendung Media Foundation prozessübergreifenden Verwendung ist der geschützte Medienpfad (Protected Media Path, PMP). Diese Hinweise gelten jedoch für jede Situation, in der Media Foundation-APIs über RPC verwendet werden.

Alle Implementierungen vonASYNCCallback sollten MTA-kompatibel sein. Diese Objekte müssen überhaupt keine COM-Objekte sein. Wenn sie dies jedoch sind, können sie nicht im STA ausgeführt werden. DieASYNCAsyncCallback::Invoke-Funktion wird in einem MTA-Arbeitsqueuethread aufgerufen, und das bereitgestellteASYNCResult-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, die sich um COM sorgen müssen. Einige Komponenten, z. B. Transformationen oder Bytestreamhandler, sind vollständige COM-Objekte, die von CLSID erstellt werden. Diese Objekte müssen die Regeln für COM-Apartments sowohl für prozessübergreifende als auch für prozessübergreifende Media Foundation. Andere Media Foundation 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.

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

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

Schnittstelle Category Erforderliches Apartment
ACTIVate Prozessübergreifender Proxy Freethreading oder neutral
VERERBByteStreamHandler COM-Objekt MTA
VERERBContentProtectionManager Prozessübergreifender Proxy Freethreading oder neutral
VERERBungsqualityManager COM-Objekt Freethreading oder neutral
VERSIERTMediaSource Prozessübergreifender Proxy Freethreading oder neutral
VERERBungshandler COM-Objekt MTA
TOPOLoader COM-Objekt Freethreading oder neutral
VORÜBERSETZUNGTransform COM-Objekt MTA

Je nach Implementierung gibt es möglicherweise zusätzliche Anforderungen. Wenn z. B. eine Mediensenke eine andere Schnittstelle implementiert, die es der Anwendung ermöglicht, direkte Funktionsaufrufe an die Senke zu tätigen, muss die Senke über einen Freethread oder neutral sein, damit sie direkte prozessübergreifende Aufrufe verarbeiten kann. Jedes Objekt kann ein Freethreading sein. In dieser Tabelle werden die Mindestanforderungen angegeben.

Die empfohlene Methode zum Implementieren von Freethread-Objekten oder neutralen Objekten ist das Aggregieren des Freethread-Marshallers. 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 nicht um das Marshallen von STA-Eingabezeigen in Freethreadkomponenten kümmern.

Komponenten, die die Long-Function-Arbeitswarteschlange (MFASYNC _ CALLBACK _ QUEUE LONG _ _ FUNCTION) verwenden, müssen mehr Sorgfalt üben. Threads in der long-Funktionsarbeitsqueue erstellen ihr eigenes STA. Komponenten, die die long-Funktionsarbeitsqueue für Rückrufe verwenden, sollten das Erstellen von COM-Objekten in diesen Threads vermeiden und darauf achten, Proxys bei Bedarf an das STA zu marshallen.

Zusammenfassung

Anwendungen haben eine einfachere Zeit, wenn sie mit Media Foundation aus einem MTA-Thread interagieren, aber es ist möglich, Media Foundation aus einem STA-Thread zu verwenden. Media Foundation keine STA-Komponenten verarbeitet, 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 Plattform-APIs

Media Foundation-Architektur