Medienereignisgeneratoren

Media Foundation bietet eine konsistente Möglichkeit für Objekte zum Senden von Ereignissen. Ein -Objekt kann Ereignisse verwenden, um die Vervollständigung einer asynchronen Methode zu signalisieren oder die Anwendung über eine Änderung des Objektzustands zu benachrichtigen.

Wenn ein Objekt Ereignisse sendet, macht es die IMFMediaEventGenerator-Schnittstelle verfügbar. Wenn das Objekt ein neues Ereignis sendet, wird das Ereignis in einer Warteschlange platziert. Die Anwendung kann das nächste Ereignis von der Warteschlange anfordern, indem sie eine der folgenden Methoden aufruft:

Die GetEvent-Methode ist synchron. Wenn sich bereits ein Ereignis in der Warteschlange befindet, gibt die Methode sofort zurück. Wenn kein Ereignis in der Warteschlange vorhanden ist, schlägt die Methode entweder sofort fehl oder blockiert, bis das nächste Ereignis in die Warteschlange gestellt wird, je nachdem, welches Flag Sie an GetEvent übergeben.

Die BeginGetEvent-Methode ist asynchron, sodass sie nie blockiert wird. Diese Methode verwendet einen Zeiger auf die IMFAsyncCallback-Schnittstelle , die von der Anwendung implementiert werden muss. Wenn der Rückruf aufgerufen wird, ruft die Anwendung IMFMediaEventGenerator::EndGetEvent auf, um das Ereignis aus der Warteschlange abzurufen. Weitere Informationen zu IMFAsyncCallback finden Sie unter Asynchrone Rückrufmethoden.

Ereignisse werden durch die IMFMediaEvent-Schnittstelle dargestellt. Diese Schnittstelle verfügt über die folgenden Methoden:

  • GetType: Ruft den Ereignistyp ab. Der Ereignistyp gibt an, was passiert ist, um das Ereignis auszulösen.

  • GetStatus: Ruft einen HRESULT-Wert ab, der angibt, ob der Vorgang, der das Ereignis ausgelöst hat, erfolgreich war. Wenn ein Vorgang asynchron fehlschlägt, gibt GetStatus einen Fehlercode zurück.

  • GetValue: Ruft eine PROPVARIANT-Instanz ab, die Ereignisdaten enthält. Die Ereignisdaten hängen vom Ereignistyp ab. Einige Ereignisse enthalten keine Daten.

  • GetExtendedType: Ruft eine GUID ab. Diese Methode gilt für das MEExtendedType-Ereignis und bietet eine Möglichkeit, benutzerdefinierte Ereignisse zu definieren.

Die IMFMediaEvent-Schnittstelle erbt auch die IMFAttributes-Schnittstelle . Einige Ereignisse enthalten zusätzliche Informationen als Attribute.

Eine Liste der Ereignistypen und der zugehörigen Daten und Attribute finden Sie unter Media Foundation-Ereignisse.

Implementieren von IMFMediaEventGenerator

Wenn Sie eine Plug-In-Komponente für Media Foundation schreiben, z. B. eine benutzerdefinierte Medienquelle oder mediensenke, müssen Sie möglicherweise IMFMediaEventGenerator implementieren. Um dies zu vereinfachen, stellt Media Foundation ein Hilfsobjekt bereit, das eine Ereigniswarteschlange implementiert. Erstellen Sie die Ereigniswarteschlange, indem Sie die MFCreateEventQueue-Funktion aufrufen. Die Ereigniswarteschlange macht die IMFMediaEventQueue-Schnittstelle verfügbar. Rufen Sie in der Implementierung der IMFMediaEventGenerator-Methoden ihres Objekts die entsprechende Methode in der Ereigniswarteschlange auf.

Das Ereigniswarteschlangenobjekt ist threadsicher. Halten Sie beim Aufrufen von GetEvent und QueueEvent niemals dasselbe kritische Abschnittsobjekt bereit, da GetEvent das Warten auf QueueEvent möglicherweise unbegrenzt blockiert. Wenn Sie denselben kritischen Abschnitt für beide Methoden haben, führt dies zu einem Deadlock.

Rufen Sie vor dem Freigeben der Ereigniswarteschlange IMFMediaEventQueue::Shutdown auf, um die Ressourcen freizugeben, die das Objekt enthält.

Wenn Ihr Objekt ein Ereignis auslösen muss, rufen Sie eine der folgenden Methoden für die Ereigniswarteschlange auf:

Diese Methoden platzieren ein neues Ereignis in der Warteschlange und signalisieren jeden Aufrufer, der auf das nächste Ereignis wartet.

Der folgende Code zeigt eine Klasse, die IMFMediaEventGenerator mithilfe dieses Hilfsobjekts implementiert. Diese Klasse definiert eine öffentliche Shutdown-Methode , die die Ereigniswarteschlange herunterfährt und den Ereigniswarteschlangenzeiger freigibt. Dieses Verhalten ist typisch für Medienquellen und Mediensenken, die immer über eine Shutdown-Methode verfügen.

class MyObject : public IMFMediaEventGenerator
{
private:
    long                m_nRefCount;    // Reference count.
    CRITICAL_SECTION    m_critSec;      // Critical section.
    IMFMediaEventQueue *m_pQueue;       // Event queue.
    BOOL                m_bShutdown;    // Is the object shut down?

    // CheckShutdown: Returns MF_E_SHUTDOWN if the object was shut down.
    HRESULT CheckShutdown() const 
    {
        return (m_bShutdown? MF_E_SHUTDOWN : S_OK);
    }

public:
    MyObject(HRESULT &hr) : m_nRefCount(0), m_pQueue(NULL), m_bShutdown(FALSE)
    {
        InitializeCriticalSection(&m_critSec);
        
        // Create the event queue.
        hr = MFCreateEventQueue(&m_pQueue);
    }

    // Shutdown: Shuts down this object.
    HRESULT Shutdown()
    {
        EnterCriticalSection(&m_critSec);

        HRESULT hr = CheckShutdown();
        if (SUCCEEDED(hr))
        {
            // Shut down the event queue.
            if (m_pQueue)
            {
                hr = m_pQueue->Shutdown();
            }

            // Release the event queue.
            SAFE_RELEASE(m_pQueue);
            // Release any other objects owned by the class (not shown).

            // Set the shutdown flag.
            m_bShutdown = TRUE;
        }

        LeaveCriticalSection(&m_critSec);
        return hr;
    }

    // TODO: Implement IUnknown (not shown).
    STDMETHODIMP_(ULONG) AddRef();
    STDMETHODIMP_(ULONG) Release();
    STDMETHODIMP QueryInterface(REFIID iid, void** ppv);

    // IMFMediaEventGenerator::BeginGetEvent
    STDMETHODIMP BeginGetEvent(IMFAsyncCallback* pCallback, IUnknown* pState)
    {
        EnterCriticalSection(&m_critSec);

        HRESULT hr = CheckShutdown();
        if (SUCCEEDED(hr))
        {
            hr = m_pQueue->BeginGetEvent(pCallback, pState);
        }

        LeaveCriticalSection(&m_critSec);
        return hr;    
    }

    // IMFMediaEventGenerator::EndGetEvent
    STDMETHODIMP EndGetEvent(IMFAsyncResult* pResult, IMFMediaEvent** ppEvent)
    {
        EnterCriticalSection(&m_critSec);

        HRESULT hr = CheckShutdown();
        if (SUCCEEDED(hr))
        {
            hr = m_pQueue->EndGetEvent(pResult, ppEvent);
        }

        LeaveCriticalSection(&m_critSec);
        return hr;    
    }

    // IMFMediaEventGenerator::GetEvent
    STDMETHODIMP GetEvent(DWORD dwFlags, IMFMediaEvent** ppEvent)
    {
        // Because GetEvent can block indefinitely, it requires
        // a slightly different locking strategy.
        IMFMediaEventQueue *pQueue = NULL;

        // Hold lock.
        EnterCriticalSection(&m_critSec);

        // Check shutdown
        HRESULT hr = CheckShutdown();

        // Store the pointer in a local variable, so that another thread
        // does not release it after we leave the critical section.
        if (SUCCEEDED(hr))
        {
            pQueue = m_pQueue;
            pQueue->AddRef();
        }

        // Release the lock.
        LeaveCriticalSection(&m_critSec);

        if (SUCCEEDED(hr))
        {
            hr = pQueue->GetEvent(dwFlags, ppEvent);
        }

        SAFE_RELEASE(pQueue);
        return hr;
    }

    // IMFMediaEventGenerator::QueueEvent
    STDMETHODIMP QueueEvent(
        MediaEventType met, REFGUID extendedType, 
        HRESULT hrStatus, const PROPVARIANT* pvValue)
    {
        EnterCriticalSection(&m_critSec);

        HRESULT hr = CheckShutdown();
        if (SUCCEEDED(hr))
        {
            hr = m_pQueue->QueueEventParamVar(
                met, extendedType, hrStatus, pvValue);
        }

        LeaveCriticalSection(&m_critSec);
        return hr;
    }

private:

    // The destructor is private. The caller must call Release.
    virtual ~MyObject()
    {
        assert(m_bShutdown);
        assert(m_nRefCount == 0);
    }
};

Media Foundation Platform-APIs