Generatory zdarzeń multimedialnych
Program Media Foundation zapewnia spójny sposób wysyłania zdarzeń przez obiekty. Obiekt może używać zdarzeń do sygnalizowania ukończenia metody asynchronicznej lub powiadamiania aplikacji o zmianie stanu obiektu.
Jeśli obiekt wysyła zdarzenia, uwidacznia interfejs IMFMediaEventGenerator. Za każdym razem, gdy obiekt wysyła nowe zdarzenie, zdarzenie jest umieszczane w kolejce. Aplikacja może zażądać kolejnego zdarzenia z kolejki, wywołując jedną z następujących metod:
Metoda GetEvent jest synchroniczna. Jeśli zdarzenie znajduje się już w kolejce, metoda zwraca natychmiast. Jeśli w kolejce nie ma żadnego zdarzenia, metoda kończy się niepowodzeniem natychmiast lub blokuje do momentu kolejkowania następnego zdarzenia, w zależności od flagi przekazywanej do GetEvent.
Metoda BeginGetEvent jest asynchroniczna, więc nigdy nie blokuje. Ta metoda przyjmuje wskaźnik do interfejsu IMFAsyncCallback, który musi zaimplementować aplikacja. Po wywołaniu wywołania zwrotnego aplikacja wywołuje IMFMediaEventGenerator::EndGetEvent, aby pobrać zdarzenie z kolejki. Aby uzyskać więcej informacji na temat IMFAsyncCallback, zobacz Asynchroniczne metody wywołania zwrotnego.
Zdarzenia są reprezentowane przez interfejs IMFMediaEvent. Ten interfejs ma następujące metody:
GetType: pobiera typ zdarzenia. Typ zdarzenia wskazuje, co się stało, aby wyzwolić zdarzenie.
GetStatus: pobiera wartość HRESULT wskazującą, czy operacja, która wyzwoliła zdarzenie, zakończyła się pomyślnie. Jeśli operacja nie powiedzie się asynchronicznie, getStatus zwraca kod błędu.
GetValue: pobiera PROPVARIANT zawierające dane zdarzenia. Dane zdarzenia zależą od typu zdarzenia. Niektóre zdarzenia nie mają żadnych danych.
GetExtendedType: pobiera identyfikator GUID. Ta metoda ma zastosowanie do MEExtendedType Eventi zapewnia sposób definiowania zdarzeń niestandardowych.
Interfejs IMFMediaEvent dziedziczy również interfejs IMFAttributes. Niektóre zdarzenia zawierają dodatkowe informacje jako atrybuty.
Aby uzyskać listę typów zdarzeń i skojarzonych z nimi danych i atrybutów, zobacz Media Foundation Events.
Implementowanie modułu IMFMediaEventGenerator
Jeśli piszesz składnik wtyczki dla programu Media Foundation, taki jak niestandardowe źródło multimediów lub ujście multimediów, może być konieczne zaimplementowanie IMFMediaEventGenerator. Aby to ułatwić, program Media Foundation udostępnia obiekt pomocnika, który implementuje kolejkę zdarzeń. Utwórz kolejkę zdarzeń, wywołując funkcję MFCreateEventQueue. Kolejka zdarzeń uwidacznia interfejsIMFMediaEventQueue. W implementacji obiektu metody IMFMediaEventGenerator wywołaj odpowiednią metodę w kolejce zdarzeń.
Obiekt kolejki zdarzeń jest bezpieczny wątkiem. Nigdy nie przechowuj tego samego obiektu sekcji krytycznej podczas wywoływania GetEvent i QueueEvent, ponieważ GetEvent może blokować oczekiwanie na QueueEvent. Jeśli przechowujesz tę samą sekcję krytyczną dla obu metod, spowoduje to zakleszczenie.
Przed zwolnieniem kolejki zdarzeń wywołaj metodę IMFMediaEventQueue::Shutdown, aby zwolnić zasoby przechowywane przez obiekt.
Gdy obiekt musi zgłosić zdarzenie, wywołaj jedną z następujących metod w kolejce zdarzeń:
Te metody umieszczają nowe zdarzenie w kolejce i sygnalizują wszelkie wywołujące oczekujące na następne zdarzenie.
Poniższy kod przedstawia klasę, która implementuje IMFMediaEventGenerator przy użyciu tego obiektu pomocniczego. Ta klasa definiuje publiczną metodę Shutdown, która zamyka kolejkę zdarzeń i zwalnia wskaźnik kolejki zdarzeń. Takie zachowanie jest typowe w przypadku źródeł multimedialnych i ujść multimediów, które zawsze mają metodę 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);
}
};
Tematy pokrewne
-
interfejsy API platformy Media Foundation