Media Foundation und COM
Microsoft Media Foundation verwendet eine Mischung aus COM-Konstrukten, ist jedoch keine vollständig COM-basierte API. In diesem Thema werden die Interaktionen 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, subtile Programmierfehler vermeiden.
- Bewährte Methoden für Anwendungen
- Bewährte Methoden für Media Foundation-Komponenten
- Zusammenfassung
- Verwandte Themen
Bewährte Methoden für Anwendungen
In Media Foundation werden die asynchrone Verarbeitung und Rückrufe von Arbeitswarteschlangen behandelt. Arbeitswarteschlangen verfügen stets über Multithread-Apartment (MTA)-Threads. Eine Anwendung kann so einfacher implementiert werden, wenn sie in einem MTA-Thread ausgeführt wird. Daher wird der Aufruf von CoInitializeEx mit dem Flag COINIT_MULTITHREADED empfohlen.
Media Foundation marshallt keine Singlethread-Apartment (STA)-Objekte für Arbeitswarteschlangenthreads. Es wird auch nicht sichergestellt, dass STA-Invarianten beibehalten werden. Daher darf eine STA-Anwendung keine STA-Objekte oder -Proxys an Media Foundation-APIs übergeben. Nur-STA-Objekte werden in Media Foundation nicht unterstützt.
Wenn Sie über einen STA-Proxy für ein MTA- oder Freethreadobjekt verfügen, kann das Objekt über einen Arbeitswarteschlangenrückruf zu einem MTA-Proxy gemarshallt werden. Die Funktion CoCreateInstance kann abhängig vom in der Registrierung für diese CLSID definierten Objektmodell 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.
Nehmen wir an, Sie möchten einen IPropertyStore-Zeiger an die Methode IMFSourceResolver::BeginCreateObjectFromURL übergeben. Sie könnten PSCreateMemoryPropertyStore aufrufen, um den IPropertyStore-Zeiger zu erstellen. Wenn Sie den Aufruf über ein STA ausführen, müssen Sie den Zeiger marshallen, bevor Sie ihn an BeginCreateObjectFromURL übergeben.
Der folgende Code zeigt, wie Sie einen STA-Proxy zu einer 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. Wenn Sie Media Foundation prozessintern verwenden, kann es sich bei diesen Objekten um MTA-Proxys handeln und sollten zu einem STA-Thread gemarshallt werden, wenn sie dort benötigt werden. Ebenso sind Objekte, die innerhalb eines Rückrufs abgerufen werden, z. B. eine Topologie, die aus dem Ereignis MESessionTopologyStatus abgerufen wird, bei prozessinterner Verwendung von Media Foundation direkte Zeiger, bei prozessübergreifender Verwendung von Media Foundation jedoch MTA-Proxys.
Hinweis
Das häufigste Szenario für die prozessübergreifende Verwendung von Media Foundation ist die Verwendung mit dem geschützten 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 keine COM-Objekte sein. Wenn Sie jedoch COM-Objekte sind, können sie nicht im STA ausgeführt werden. Die Funktion IMFAsyncCallback::Invoke wird für einen MTA-Arbeitswarteschlangenthread aufgerufen. 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, für die COM eine Rolle spielt. Einige Komponenten, z. B. Transformationen oder Bytedatenstromhandler, sind vollständige, von CLSID erstellte COM-Objekte. Diese Objekte müssen sowohl bei prozessinterner als auch bei prozessübergreifender Verwendung von Media Foundation den Regeln für COM-Apartments folgen. Andere Media Foundation-Komponenten sind keine vollständigen COM-Objekte, benötigen jedoch COM-Proxys für die prozessübergreifende Wiedergabe. Die Objekte in dieser Kategorie sind Medienquellen und Aktivierungsobjekte. Diese Objekte können Apartmentprobleme ignorieren, wenn Media Foundation nur prozessintern verwendet wird.
Obwohl es sich nicht bei allen Media Foundation-Objekten um COM-Objekte handelt, 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 Referenzzählung und QueryInterface. Alle gezählten Referenzobjekte sollten auch sicherstellen, dass DllCanUnloadNow kein Entladen des Moduls zulässt, während die Objekte noch vorhanden sind.
Media Foundation-Komponenten dürfen keine STA-Objekte sein. Zahlreiche Media Foundation-Objekte müssen keine COM-Objekte sein. Wenn Sie jedoch COM-Objekte sind, können sie nicht im STA ausgeführt werden. Alle Media Foundation-Komponenten müssen threadsicher sein. Einige Media Foundation-Objekte müssen außerdem Freethreadobjekte oder apartmentneutral sein. In der folgenden Tabelle werden die Anforderungen für benutzerdefinierte Schnittstellenimplementierungen angegeben:
Schnittstelle | Kategorie | Erforderliches Apartment |
---|---|---|
IMFActivate | Prozessübergreifender Proxy | Freethread oder neutral |
IMFByteStreamHandler | COM-Objekt | MTA |
IMFContentProtectionManager | Prozessübergreifender Proxy | Freethread oder neutral |
IMFQualityManager | COM-Objekt | Freethread oder neutral |
IMFMediaSource | Prozessübergreifender Proxy | Freethread oder neutral |
IMFSchemeHandler | COM-Objekt | MTA |
IMFTopoLoader | COM-Objekt | Freethread oder neutral |
IMFTransform | COM-Objekt | MTA |
Abhängig von der Implementierung gibt es möglicherweise zusätzliche Anforderungen. Wenn beispielsweise eine Mediensenke eine andere Schnittstelle implementiert, über die die Anwendung direkte Funktionsaufrufe an die Senke ausführen kann, müsste es sich um eine apartmentneutrale oder Freethreadsenke handeln, damit sie direkte prozessübergreifende Aufrufe verarbeiten kann. Jedes Objekt kann ein Freethreadobjekt sein. In dieser Tabelle werden die Mindestanforderungen aufgelistet.
Die empfohlene Methode für die Implementierung von apartmentneutralen oder Freethreadobjekten besteht in der Aggregierung des Freethread-Marshaler. Weitere Informationen finden Sie unter CoCreateFreeThreadedMarshaler. Aufgrund der Anforderung, dass keine STA-Objekte oder -Proxys an Media Foundation-APIs übergeben werden dürfen, müssen Freethreadobjekte keine STA-Eingabezeiger in Freethreadkomponenten marshallen.
Bei Komponenten, die die Langfunktions-Arbeitswarteschlange (MFASYNC_CALLBACK_QUEUE_LONG_FUNCTION) verwenden, müssen Sie vorsichtiger sein. Threads in Langfunktions-Arbeitswarteschlangen erstellen ein eigenes STA. Komponenten, die die Langfunktions-Arbeitswarteschlange für Rückrufe verwenden, sollten das Erstellen von COM-Objekten in diesen Threads vermeiden und müssen Proxys zum STA marshallen, wenn notwendig.
Zusammenfassung
Es ist zwar einfacher, wenn Anwendungen über einen MTA-Thread mit Media Foundation interagieren, mit etwas Sorgfalt kann Media Foundation jedoch auch über einen STA-Thread verwendet werden. Media Foundation behandelt keine STA-Komponenten. Anwendungen dürfen keine STA-Objekte an Media Foundation-APIs übergeben. Für einige Objekte gibt es zusätzliche Anforderungen, insbesondere für Objekte, die prozessübergreifend ausgeführt werden. Wenn Sie diese Richtlinien befolgen, können COM-Fehler, Deadlocks und unerwartete Verzögerungen bei der Medienverarbeitung vermieden werden.
Zugehörige Themen