Geradores de Eventos de Mídia
O Media Foundation fornece uma maneira consistente de 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 enviar eventos, ele exporá a interface IMFMediaEventGenerator . 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 bloqueará até que o próximo evento seja enfileirado, dependendo de qual sinalizador você passar para GetEvent.
O método BeginGetEvent é assíncrono, portanto, ele nunca bloqueia. Esse método usa um ponteiro para a interface IMFAsyncCallback , 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 . Essa interface tem os seguintes métodos:
GetType: recupera o tipo de evento. O tipo de evento indica o que aconteceu para disparar o evento.
GetStatus: recupera um valor 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 evento. 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 evento MEExtendedType e fornece uma maneira de definir eventos personalizados.
A interface IMFMediaEvent também herda a interface IMFAttributes . Alguns eventos têm 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ção MFCreateEventQueue . A fila de eventos expõe a interface IMFMediaEventQueue . Na implementação do objeto dos métodos IMFMediaEventGenerator , 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ítico ao chamar GetEvent e QueueEvent, pois GetEvent pode bloquear a espera indefinida por QueueEvent. Se você mantiver a mesma seção crítica para ambos os métodos, isso causará um deadlock.
Antes de liberar a fila de eventos, chame IMFMediaEventQueue::Shutdown para liberar os recursos que o objeto conté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 de Desligamento público 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);
}
};
Tópicos relacionados