Sdílet prostřednictvím


Generátory událostí médií

Media Foundation poskytuje konzistentní způsob odesílání událostí objektů. Objekt může pomocí událostí signalizovat dokončení asynchronní metody nebo upozornit aplikaci na změnu ve stavu objektu.

Pokud objekt odesílá události, zveřejňuje MMFMediaEventGenerator rozhraní. Kdykoli objekt odešle novou událost, událost se umístí do fronty. Aplikace může požádat o další událost z fronty voláním jedné z následujících metod:

Metoda GetEvent je synchronní. Pokud je událost již ve frontě, metoda vrátí okamžitě. Pokud ve frontě není žádná událost, metoda buď selže okamžitě, nebo blokuje, dokud se další událost nezařadí do fronty v závislosti na tom, který příznak předáte GetEvent.

Metoda BeginGetEvent je asynchronní, takže nikdy neblokuje. Tato metoda přebírá ukazatel na MMFAsyncCallback rozhraní, které musí aplikace implementovat. Při vyvolání zpětného volání aplikace volá MMFMediaEventGenerator::EndGetEvent získat událost z fronty. Další informace o MMFAsyncCallbacknaleznete v tématu asynchronní metody zpětného volání.

Události jsou reprezentovány rozhraním MMFMediaEvent. Toto rozhraní má následující metody:

  • GetType: Načte typ události. Typ události označuje, co se stalo s aktivací události.

  • GetStatus: Načte hodnotu HRESULT označující, jestli byla operace, která událost aktivovala, úspěšná. Pokud operace asynchronně selže, GetStatus vrátí kód selhání.

  • GetValue: Načte PROPVARIANT, který obsahuje data událostí. Data události závisí na typu události. Některé události neobsahují žádná data.

  • GetExtendedType: Načte identifikátor GUID. Tato metoda se vztahuje na MEExtendedType Událosta poskytuje způsob, jak definovat vlastní události.

Rozhraní MMFMediaEvent také dědí rozhraní MMFAttributes rozhraní. Některé události obsahují další informace jako atributy.

Seznam typů událostí a jejich přidružených dat a atributů naleznete v tématu Media Foundation Events.

Implementace MMFMediaEventGenerator

Pokud píšete součást modulu plug-in pro Media Foundation, jako je vlastní zdroj médií nebo jímka médií, možná budete muset implementovat MMFMediaEventGenerator. Pro zjednodušení poskytuje Media Foundation pomocný objekt, který implementuje frontu událostí. Vytvořte frontu událostí voláním funkce MFCreateEventQueue. Fronta událostí zveřejňuje rozhraní MMFMediaEventQueue. V implementaci objektu MMFMediaEventGenerator metody volejte odpovídající metodu ve frontě událostí.

Objekt fronty událostí je bezpečný pro vlákno. Při volání GetEvent a QueueEventnikdy neudržujte stejný objekt kritického oddílu, protože GetEvent může QueueEvent blokovat. Pokud u obou metod uchováváte stejnou kritickou část, způsobí zablokování.

Před vydáním fronty událostí zavolejte MMFMediaEventQueue::Shutdown uvolnit prostředky, které objekt obsahuje.

Pokud objekt potřebuje vyvolat událost, zavolejte jednu z následujících metod ve frontě událostí:

Tyto metody umístí novou událost do fronty a signalizují všechny volající, kteří čekají na další událost.

Následující kód ukazuje třídu, která implementuje MMFMediaEventGenerator pomocí tohoto pomocného objektu. Tato třída definuje veřejnou Shutdown metoda, která vypne frontu událostí a uvolní ukazatel fronty událostí. Toto chování by bylo typické pro zdroje médií a jímky médií, které vždy mají metodu Vypnout.

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);
    }
};

rozhraní API platformy Media Foundation