媒體事件產生器
媒體基礎為對象傳送事件提供一致的方式。 物件可以使用事件來發出異步方法完成的訊號,或通知應用程式有關物件狀態的變更。
如果對象傳送事件,則會公開IMFMediaEventGenerator介面。 每當物件傳送新的事件時,事件就會放在佇列中。 應用程式可以呼叫下列其中一種方法,從佇列要求下一個事件:
GetEvent 方法是同步的。 如果事件已經在佇列中,方法會立即傳回。 如果佇列中沒有任何事件,方法會立即失敗,或封鎖直到下一個事件排入佇列為止,視您傳入的旗標而定 GetEvent。
BeginGetEvent 方法是異步的,因此絕不會封鎖。 這個方法會採用應用程式必須實作 IMFAsyncCallback 介面的指標。 叫用回呼時,應用程式會呼叫 IMFMediaEventGenerator::EndGetEvent,以從佇列取得事件。 如需 IMFAsyncCallback的詳細資訊,請參閱 異步回呼方法。
事件是由IMFMediaEvent介面表示。 此介面具有下列方法:
GetType:擷取事件類型。 事件類型表示觸發事件所發生的情況。
GetStatus:擷取 HRESULT 值,指出觸發事件的作業是否成功。 如果作業以異步方式失敗,GetStatus 會傳回失敗碼。
GetValue:擷取包含事件數據的 PROPVARIANT。 事件數據取決於事件類型。 某些事件沒有任何數據。
GetExtendedType:擷取 GUID。 此方法適用於 MEExtendedType事件,並提供定義自定義事件的方式。
IMFMediaEvent 介面也會繼承 imfAttributes介面。 某些事件會將其他資訊當作屬性。
如需事件類型及其相關聯資料和屬性的清單,請參閱 Media Foundation Events。
實作IMFMediaEventGenerator
如果您要撰寫媒體基礎的外掛程式元件,例如自訂媒體來源或媒體接收,您可能需要實作 IMFMediaEventGenerator。 為了讓這更容易,Media Foundation 會提供實作事件佇列的協助程序物件。 呼叫 MFCreateEventQueue 函式,以建立事件佇列。 事件佇列會公開 IMFMediaEventQueue介面。 在 IMFMediaEventGenerator 方法的 實作中,呼叫事件佇列上的對應方法。
事件佇列物件是安全線程。 呼叫 getEvent和 QueueEvent時,永遠不要保留相同的重要區段對象,因為 GetEvent 可能會無限期地等候 queueEvent。 如果您同時保留這兩種方法的相同重要區段,則會導致死結。
在釋放事件佇列之前,請呼叫 IMFMediaEventQueue::Shutdown 釋放物件保留的資源。
當您的物件需要引發事件時,請在事件佇列上呼叫下列其中一種方法:
這些方法會將新事件放在佇列上,併發出任何正在等候下一個事件的呼叫端發出訊號。
下列程式代碼顯示類別,這個類別會使用此協助程式對象實作 IMFMediaEventGenerator。 這個類別會定義公用 Shutdown 方法來關閉事件佇列並釋放事件佇列指標。 此行為通常是媒體來源和媒體接收,其一律具有 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);
}
};
相關主題