Media Foundation och COM
Microsoft Media Foundation använder en blandning av COM-konstruktioner, men är inte ett helt COM-baserat API. I det här avsnittet beskrivs interaktionen mellan COM och Media Foundation. Den definierar också några metodtips för att utveckla Media Foundation-plugin-komponenter. Genom att följa dessa metoder kan du undvika några vanliga men subtila programmeringsfel.
Metodtips för program
I Media Foundation hanteras asynkron bearbetning och återanrop av arbetsköer. Arbetsköer har alltid MTA-trådar (multithreaded apartment), så ett program får en enklare implementering om det körs på en MTA-tråd också. Därför rekommenderar vi att du anropar CoInitializeEx med flaggan COINIT_MULTITHREADED.
Media Foundation konverterar inte sta-objekt (single-threaded apartment) till arbetskötrådar. Det säkerställer inte heller att STA-invarianter bibehålls. Därför måste ett STA-program vara noga med att inte skicka STA-objekt eller proxyservrar till Media Foundation-API:er. Objekt som endast är STA stöds inte i Media Foundation.
Om du har en STA-proxy till ett MTA- eller fritrådat objekt kan objektet konverteras till en MTA-proxy med hjälp av ett återanrop till arbetskön. Funktionen CoCreateInstance kan returnera antingen en råpekare eller en STA-proxy, beroende på den objektmodell som definierats i registret för det CLSID. Om en STA-proxy returneras får du inte skicka pekaren till ett Media Foundation-API.
Anta till exempel att du vill skicka en IPropertyStore- pekare till metoden IMFSourceResolver::BeginCreateObjectFromURL. Du kan anropa PSCreateMemoryPropertyStore för att skapa pekaren IPropertyStore. Om du anropar från en STA måste du konvertera pekaren innan du skickar den till BeginCreateObjectFromURL.
Följande kod visar hur du konverterar en STA-proxy till ett Media Foundation-API.
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;
};
Mer information om den globala gränssnittstabellen finns i IGlobalInterfaceTable.
Om du använder Media Foundation i processen är objekt som returneras från Media Foundation-metoder och funktioner direktpekare till objektet. För Media Foundation mellan processer kan dessa objekt vara MTA-proxyservrar och bör konverteras till en STA-tråd om det behövs där. På samma sätt är objekt som hämtas i ett återanrop – till exempel en topologi från händelsen MESessionTopologyStatus – direktpekare när Media Foundation används i processen, men är MTA-proxyservrar när Media Foundation används mellan processer.
Not
Det vanligaste scenariot för att använda Media Foundation-korsprocesser är med Protected Media Path (PMP). Dessa kommentarer gäller dock för alla situationer när Media Foundation-API:er används via RPC.
Alla implementeringar av IMFAsyncCallback bör vara MTA-kompatibla. Dessa objekt behöver inte vara COM-objekt alls. Men om de är det, kan de inte springa i STA. Funktionen IMFAsyncCallback::Invoke anropas på en MTA-arbetsfrågatråd, och den angivna IMFAsyncResult-objektet är antingen en direkt objektpekare eller en MTA-proxy.
Metodtips för Media Foundation-komponenter
Det finns två kategorier av Media Foundation-objekt som måste vara bekymrade över COM. Vissa komponenter, till exempel transformeringar eller byteströmhanterare, är fullständiga COM-objekt som skapats av CLSID. Dessa objekt måste följa reglerna för COM-lägenheter, både för processbaserade och processöverskridande Media Foundation. Andra Media Foundation-komponenter är inte fullständiga COM-objekt, men behöver COM-proxyservrar för uppspelning mellan processer. Objekt i den här kategorin är mediekällor och aktiveringsobjekt. De här objekten kan ignorera lägenhetsproblem om de endast används för Media Foundation.
Även om inte alla Media Foundation-objekt är COM-objekt härleds alla Media Foundation-gränssnitt från IUnknown. Därför måste alla Media Foundation-objekt implementera IUnknown- enligt COM-specifikationer, inklusive reglerna för referensräkning och QueryInterface. Alla refererade objekt bör också se till att DllCanUnloadNow inte tillåter att modulen tas bort medan objekten fortfarande finns kvar.
Media Foundation-komponenter kan inte vara STA-objekt. Många Media Foundation-objekt behöver inte vara COM-objekt alls. Men om de är det, kan de inte springa i STA. Alla Media Foundation-komponenter måste vara trådsäkra. Vissa Media Foundation-objekt måste också vara fritrådade eller lägenhetsneutrala. I följande tabell anges kraven för implementeringar av anpassade gränssnitt:
Gränssnitt | Kategori | Obligatorisk lägenhet |
---|---|---|
IMFAktivera | Korsprocessproxy | Fritrådad eller neutral |
IMFByteStreamHandler | COM-objekt | MTA |
IMFContentProtectionManager | Korsprocessproxy | Fritrådad eller neutral |
IMFQualityManager | COM-objekt | Fritrådad eller neutral |
IMFMediaSource | Korsprocessproxy | Fritrådad eller neutral |
IMFSchemeHandler | COM-objekt | MTA |
IMFTopoLoader | COM-objekt | Fritrådad eller neutral |
IMFTransform | COM-objekt | MTA |
Det kan finnas ytterligare krav beroende på implementeringen. Om en mediemottagare till exempel implementerar ett annat gränssnitt som gör det möjligt för programmet att göra direkta funktionsanrop till mottagaren, måste mottagaren vara fritrådad eller neutral, så att den kan hantera direkta korsprocessanrop. Alla objekt kan vara fritt trådade; den här tabellen anger minimikraven.
Det rekommenderade sättet att implementera fritrådade eller neutrala objekt är genom att aggregera den fritrådade marskalkern. Mer information finns i CoCreateFreeThreadedMarshaler. I enlighet med kravet att inte skicka STA-objekt eller proxyservrar till Media Foundation-API:er behöver fritrådade objekt inte oroa sig för att konvertera STA-indatapekare i fritrådade komponenter.
Komponenter som använder arbetskön med långa funktioner (MFASYNC_CALLBACK_QUEUE_LONG_FUNCTION) måste vara mer försiktiga. Trådar i den långa funktionsarbetskön skapar sin egen STA. Komponenter som använder den långa funktionsarbetskön för återanrop bör undvika att skapa COM-objekt på dessa trådar och måste vara noga med att konvertera proxyservrar till STA efter behov.
Sammanfattning
Program kommer att ha en enklare tid om de interagerar med Media Foundation från en MTA-tråd, men det är möjligt med viss försiktighet att använda Media Foundation från en STA-tråd. Media Foundation hanterar inte STA-komponenter och program bör vara noga med att inte skicka STA-objekt till Media Foundation-API:er. Vissa objekt har ytterligare krav, särskilt objekt som körs i en korsprocesssituation. Genom att följa dessa riktlinjer kan du undvika COM-fel, dödlägen och oväntade fördröjningar i mediebearbetningen.
Relaterade ämnen