Condividi tramite


Media Foundation e COM

Microsoft Media Foundation usa una combinazione di costrutti COM, ma non è un'API completamente basata su COM. In questo argomento viene descritta l'interazione tra COM e Media Foundation. Definisce anche alcune procedure consigliate per lo sviluppo di componenti plug-in di Media Foundation. Seguendo queste procedure è possibile evitare alcuni errori di programmazione comuni ma sottili.

Procedure consigliate per le applicazioni

In Media Foundation l'elaborazione asincrona e i callback vengono gestiti dalle code di lavoro. Le code di lavoro hanno sempre thread multithreading apartment (MTA), quindi un'applicazione avrà un'implementazione più semplice se viene eseguita anche in un thread MTA. È pertanto consigliabile chiamare CoInitializeEx con il flag COINIT_MULTITHREADED.

Media Foundation non esegue il marshalling di oggetti apartment a thread singolo (STA) per i thread della coda di lavoro. Né garantisce che le invarianti STA vengano mantenute. Pertanto, un'applicazione STA deve prestare attenzione a non passare oggetti o proxy STA alle API di Media Foundation. Gli oggetti solo STA non sono supportati in Media Foundation.

Se si dispone di un proxy STA a un oggetto MTA o a thread libero, è possibile effettuare il marshalling dell'oggetto a un proxy MTA usando un callback della coda di lavoro. La funzione CoCreateInstance può restituire un puntatore non elaborato o un proxy STA, a seconda del modello a oggetti definito nel Registro di sistema per tale CLSID. Se viene restituito un proxy STA, non è necessario passare il puntatore a un'API di Media Foundation.

Si supponga, ad esempio, di voler passare un puntatore IPropertyStore al metodo IMFSourceResolver::BeginCreateObjectFromURL. È possibile chiamare PSCreateMemoryPropertyStore per creare il puntatore IPropertyStore . Se si esegue una chiamata da un sta sta, è necessario effettuare il marshalling del puntatore prima di passarlo a BeginCreateObjectFromURL.

Il codice seguente illustra come effettuare il marshalling di un proxy STA a un'API di 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;
};

Per altre informazioni sulla tabella dell'interfaccia globale, vedere IGlobalInterfaceTable.

Se si usa Media Foundation in-process, gli oggetti restituiti dai metodi e dalle funzioni di Media Foundation sono puntatori diretti all'oggetto. Per Media Foundation tra processi, questi oggetti possono essere proxy MTA e devono essere sottoposto a marshalling in un thread STA, se necessario. Analogamente, gli oggetti ottenuti all'interno di un callback, ad esempio una topologia dall'evento MESessionTopologyStatus , sono puntatori diretti quando Media Foundation viene usato in-process, ma sono proxy MTA quando Media Foundation viene usato tra processi.

Nota

Lo scenario più comune per l'uso di Media Foundation tra processi è costituito dal percorso multimediale protetto (PMP). Tuttavia, queste osservazioni si applicano a qualsiasi situazione in cui le API di Media Foundation vengono usate tramite RPC.

 

Tutte le implementazioni di IMFAsyncCallback devono essere compatibili con MTA. Questi oggetti non devono necessariamente essere oggetti COM. Ma se sono, non possono essere eseguiti nell'sta. La funzione IMFAsyncCallback::Invoke verrà richiamata su un thread della sequenza di lavoro MTA e l'oggetto IMFAsyncResult fornito sarà un puntatore a oggetti diretto o un proxy MTA.

Procedure consigliate per i componenti di Media Foundation

Esistono due categorie di oggetti di Media Foundation che devono preoccuparsi di COM. Alcuni componenti, ad esempio trasformazioni o gestori di flusso di byte, sono oggetti COM completi creati da CLSID. Questi oggetti devono rispettare le regole per gli appartamenti COM, sia in-process che cross-process Media Foundation. Altri componenti di Media Foundation non sono oggetti COM completi, ma richiedono proxy COM per la riproduzione tra processi. Gli oggetti in questa categoria includono origini multimediali e oggetto attivazione. Questi oggetti possono ignorare i problemi di apartment se verranno usati solo per Media Foundation in-process.

Anche se non tutti gli oggetti Media Foundation sono oggetti COM, tutte le interfacce di Media Foundation derivano da IUnknown. Pertanto, tutti gli oggetti Media Foundation devono implementare IUnknown in base alle specifiche COM, incluse le regole per il conteggio dei riferimenti e QueryInterface. Tutti gli oggetti con conteggio dei riferimenti devono anche assicurarsi che DllCanUnloadNow non consenta il caricamento del modulo mentre gli oggetti rimangono persistenti.

I componenti di Media Foundation non possono essere oggetti STA. Molti oggetti Media Foundation non devono necessariamente essere oggetti COM. Ma se sono, non possono essere eseguiti nell'sta. Tutti i componenti di Media Foundation devono essere thread-safe. Alcuni oggetti di Media Foundation devono anche essere a thread libero o indipendente dall'appartamento. La tabella seguente specifica i requisiti per le implementazioni dell'interfaccia personalizzata:

Interfaccia Categoria Appartamento obbligatorio
IMFActivate Proxy tra processi Thread libero o neutro
IMFByteStreamHandler Oggetto COM MTA
IMFContentProtectionManager Proxy tra processi Thread libero o neutro
IMFQualityManager Oggetto COM Thread libero o neutro
IMFMediaSource Proxy tra processi Thread libero o neutro
IMFSchemeHandler Oggetto COM MTA
IMFTopoLoader Oggetto COM Thread libero o neutro
IMFTransform Oggetto COM MTA

 

Potrebbero essere previsti requisiti aggiuntivi a seconda dell'implementazione. Ad esempio, se un sink multimediale implementa un'altra interfaccia che consente all'applicazione di effettuare chiamate di funzione dirette al sink, il sink deve essere a thread libero o neutro, in modo che possa gestire chiamate dirette tra processi. Qualsiasi oggetto può essere a thread libero; questa tabella specifica i requisiti minimi.

Il modo consigliato per implementare oggetti senza thread o neutrali consiste nell'aggregare il gestore di marshalling a thread libero. Per altri dettagli, vedere CoCreateFreeThreadedMarshaler. In conformità con il requisito di non passare oggetti o proxy STA alle API di Media Foundation, gli oggetti a thread libero non devono preoccuparsi del marshalling dei puntatori di input STA nei componenti a thread libero.

I componenti che usano la coda di lavoro con funzioni lunghe (MFASYNC_CALLBACK_QUEUE_LONG_FUNCTION) devono prestare maggiore attenzione. I thread nella coda di lavoro a funzione lunga creano la propria STA. I componenti che usano la coda di lavoro a funzione lunga per i callback devono evitare la creazione di oggetti COM in questi thread e devono prestare attenzione al marshalling dei proxy alla sta in base alle esigenze.

Riepilogo

Le applicazioni avranno un tempo più semplice se interagiscono con Media Foundation da un thread MTA, ma è possibile usare Media Foundation da un thread STA. Media Foundation non gestisce i componenti STA e le applicazioni devono prestare attenzione a non passare oggetti STA alle API di Media Foundation. Alcuni oggetti hanno requisiti aggiuntivi, in particolare gli oggetti eseguiti in una situazione tra processi. Seguendo queste linee guida è possibile evitare errori COM, deadlock e ritardi imprevisti nell'elaborazione multimediale.

API della piattaforma Media Foundation

Architettura di Media Foundation