Генераторы событий мультимедиа
Media Foundation предоставляет согласованный способ отправки событий объектам. Объект может использовать события, чтобы сигнализировать о завершении асинхронного метода или уведомлять приложение об изменении состояния объекта.
Если объект отправляет события, он предоставляет интерфейс IMFMediaEventGenerator. Каждый раз, когда объект отправляет новое событие, событие помещается в очередь. Приложение может запросить следующее событие из очереди, вызвав один из следующих методов:
Метод GetEvent синхронен. Если событие уже находится в очереди, метод возвращается немедленно. Если в очереди нет события, метод либо немедленно завершается ошибкой, либо блокируется до очереди следующего события, в зависимости от того, какой флаг передается в GetEvent.
Метод BeginGetEvent асинхронен, поэтому он никогда не блокируется. Этот метод принимает указатель на интерфейс IMFAsyncCallback, который приложение должно реализовать. При вызове обратного вызова приложение вызывает IMFMediaEventGenerator::EndGetEvent, чтобы получить событие из очереди. Дополнительные сведения о МВФAsyncCallbackсм. в асинхронных методов обратного вызова.
События представлены интерфейсом IMFMediaEvent. Этот интерфейс имеет следующие методы:
GetType: извлекает тип события. Тип события указывает, что произошло с активацией события.
GetStatus: извлекает значение HRESULT, указывающее, была ли операция, активировающая событие успешно. Если операция завершается асинхронно, GetStatus возвращает код сбоя.
GetValue: извлекает PROPVARIANT, содержащую данные события. Данные события зависят от типа события. Некоторые события не имеют данных.
GetExtendedType: извлекает GUID. Этот метод применяется к события MEExtendedTypeи предоставляет способ определения пользовательских событий.
Интерфейс IMFMediaEvent также наследует интерфейсМВФAttributes. Некоторые события содержат дополнительные сведения в качестве атрибутов.
Список типов событий и связанных с ними данных и атрибутов см. в события Media Foundation.
Реализация МВФMediaEventGenerator
Если вы пишете подключаемый модуль для Media Foundation, например пользовательский источник мультимедиа или приемник мультимедиа, может потребоваться реализовать IMFMediaEventGenerator. Чтобы упростить эту задачу, Media Foundation предоставляет вспомогательный объект, реализующий очередь событий. Создайте очередь событий, вызвав функцию MFCreateEventQueue. Очередь событий предоставляет интерфейс IMFMediaEventQueue. В реализации методов МВФMediaEventGenerator объекта вызовите соответствующий метод в очереди событий.
Объект очереди событий является потокобезопасной. Никогда не удерживайте один и тот же критический объект раздела при вызове GetEvent и QueueEvent, так как GetEvent может блокировать неограниченное время ожидания QueueEvent. Если вы держите один и тот же критический раздел для обоих методов, это приведет к взаимоблокировки.
Перед освобождением очереди событий вызовите IMFMediaEventQueue::Shutdown, чтобы освободить ресурсы, удерживаемые объектом.
Когда объекту нужно вызвать событие, вызовите один из следующих методов в очереди событий:
Эти методы помещают новое событие в очередь и сигнализируют любому вызывающей стороне, ожидающей следующего события.
В следующем коде показан класс, реализующий IMFMediaEventGenerator с помощью этого вспомогательного объекта. Этот класс определяет общедоступный метод завершения работы, который завершает очередь событий и освобождает указатель очереди событий. Это поведение будет типичным для источников мультимедиа и приемников мультимедиа, которые всегда имеют метод завершение работы.
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);
}
};
Связанные разделы