Generadores de eventos multimedia

Media Foundation proporciona una manera coherente de que los objetos envíen eventos. Un objeto puede usar eventos para indicar la finalización de un método asincrónico o para notificar a la aplicación un cambio en el estado del objeto.

Si un objeto envía eventos, expone la interfaz IMFMediaEventGenerator . Cada vez que el objeto envía un nuevo evento, el evento se coloca en una cola. La aplicación puede solicitar el siguiente evento de la cola llamando a uno de los métodos siguientes:

El método GetEvent es sincrónico. Si un evento ya está en la cola, el método devuelve inmediatamente. Si no hay ningún evento en la cola, el método produce un error inmediatamente o se bloquea hasta que se pone en cola el evento siguiente, en función de la marca que pase a GetEvent.

El método BeginGetEvent es asincrónico, por lo que nunca se bloquea. Este método toma un puntero a la interfaz IMFAsyncCallback , que la aplicación debe implementar. Cuando se invoca la devolución de llamada, la aplicación llama a IMFMediaEventGenerator::EndGetEvent para obtener el evento de la cola. Para obtener más información sobre IMFAsyncCallback, vea Métodos de devolución de llamada asincrónica.

Los eventos se representan mediante la interfaz IMFMediaEvent . Esta interfaz tiene los métodos siguientes:

  • GetType: recupera el tipo de evento. El tipo de evento indica lo que ha ocurrido para desencadenar el evento.

  • GetStatus: recupera un valor HRESULT , que indica si la operación que desencadenó el evento se realizó correctamente. Si se produce un error asincrónico en una operación, GetStatus devuelve un código de error.

  • GetValue: recupera un PROPVARIANT que contiene datos de eventos. Los datos del evento dependen del tipo de evento. Algunos eventos no tienen datos.

  • GetExtendedType: recupera un GUID. Este método se aplica al evento MEExtendedType y proporciona una manera de definir eventos personalizados.

La interfaz IMFMediaEvent también hereda la interfaz IMFAttributes . Algunos eventos llevan información adicional como atributos.

Para obtener una lista de los tipos de eventos y sus datos y atributos asociados, consulte Eventos de Media Foundation.

Implementación de IMFMediaEventGenerator

Si va a escribir un componente de complemento para Media Foundation, como un origen de medios personalizado o un receptor de medios, es posible que tenga que implementar IMFMediaEventGenerator. Para facilitar esta tarea, Media Foundation proporciona un objeto auxiliar que implementa una cola de eventos. Cree la cola de eventos llamando a la función MFCreateEventQueue . La cola de eventos expone la interfaz IMFMediaEventQueue . En la implementación del objeto de los métodos IMFMediaEventGenerator , llame al método correspondiente en la cola de eventos.

El objeto de cola de eventos es seguro para subprocesos. No contenga nunca el mismo objeto de sección crítico al llamar a GetEvent y QueueEvent, ya que GetEvent podría bloquearse indefinidamente esperando QueueEvent. Si mantiene la misma sección crítica para ambos métodos, provocará un interbloqueo.

Antes de liberar la cola de eventos, llame a IMFMediaEventQueue::Shutdown para liberar los recursos que contiene el objeto.

Cuando el objeto necesite generar un evento, llame a uno de los métodos siguientes en la cola de eventos:

Estos métodos colocan un nuevo evento en la cola y indican cualquier llamador que esté esperando el siguiente evento.

El código siguiente muestra una clase que implementa IMFMediaEventGenerator mediante este objeto auxiliar. Esta clase define un método de apagado público que cierra la cola de eventos y libera el puntero de la cola de eventos. Este comportamiento sería típico para los orígenes multimedia y los receptores de medios, que siempre tienen un 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);
    }
};

API de media Foundation Platform