Partilhar via


Geradores de eventos de mídia

O Media Foundation fornece uma maneira consistente para os objetos enviarem eventos. Um objeto pode usar eventos para sinalizar a conclusão de um método assíncrono ou para notificar o aplicativo sobre uma alteração no estado do objeto.

Se um objeto envia eventos, ele expõe a interfaceIMFMediaEventGenerator. Sempre que o objeto envia um novo evento, o evento é colocado em uma fila. O aplicativo pode solicitar o próximo evento da fila chamando um dos seguintes métodos:

O método GetEvent é síncrono. Se um evento já estiver na fila, o método retornará imediatamente. Se não houver nenhum evento na fila, o método falhará imediatamente ou será bloqueado até que o próximo evento seja enfileirado, dependendo de qual sinalizador você passar para GetEvent.

O método BeginGetEvent é assíncrono, portanto, nunca bloqueia. Esse método leva um ponteiro para o IMFAsyncCallback interface, que o aplicativo deve implementar. Quando o retorno de chamada é invocado, o aplicativo chama IMFMediaEventGenerator::EndGetEvent para obter o evento da fila. Para obter mais informações sobre IMFAsyncCallback, consulte Métodos de retorno de chamada assíncronos.

Os eventos são representados pela interface IMFMediaEvent. Esta interface tem os seguintes métodos:

  • GetType: Recupera o tipo de evento. O tipo de evento indica o que aconteceu para acionar o evento.

  • GetStatus: Recupera um valor de HRESULT, indicando se a operação que disparou o evento foi bem-sucedida. Se uma operação falhar de forma assíncrona, GetStatus retornará um código de falha.

  • GetValue: Recupera um PROPVARIANT que contém dados de eventos. Os dados do evento dependem do tipo de evento. Alguns eventos não têm dados.

  • GetExtendedType: Recupera um GUID . Esse método se aplica ao de eventos MEExtendedType e fornece uma maneira de definir eventos personalizados.

A interface IMFMediaEvent também herda a interfaceIMFAttributes. Alguns eventos carregam informações adicionais como atributos.

Para obter uma lista de tipos de eventos e seus dados e atributos associados, consulte Media Foundation Events.

Implementando IMFMediaEventGenerator

Se você estiver escrevendo um componente de plug-in para o Media Foundation, como uma fonte de mídia personalizada ou um coletor de mídia, talvez seja necessário implementar IMFMediaEventGenerator. Para facilitar isso, o Media Foundation fornece um objeto auxiliar que implementa uma fila de eventos. Crie a fila de eventos chamando a funçãoMFCreateEventQueue. A fila de eventos expõe a interfaceIMFMediaEventQueue. Na implementação do objeto dos métodos de IMFMediaEventGenerator do, chame o método correspondente na fila de eventos.

O objeto da fila de eventos é thread safe. Nunca mantenha o mesmo objeto de seção crítica ao chamar GetEvent e QueueEvent , porque GetEvent pode bloquear indefinidamente a espera por QueueEvent. Se você mantiver a mesma seção crítica para ambos os métodos, isso causará um impasse.

Antes de liberar a fila de eventos, chame IMFMediaEventQueue::Shutdown para liberar os recursos que o objeto retém.

Quando o objeto precisar gerar um evento, chame um dos seguintes métodos na fila de eventos:

Esses métodos colocam um novo evento na fila e sinalizam qualquer chamador que esteja aguardando o próximo evento.

O código a seguir mostra uma classe que implementa IMFMediaEventGenerator usando esse objeto auxiliar. Essa classe define um método público Shutdown que desliga a fila de eventos e libera o ponteiro da fila de eventos. Esse comportamento seria típico para fontes de mídia e coletores de mídia, que sempre têm um método Shutdown.

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

APIs do Media Foundation Platform