媒體事件產生器
媒體基礎為物件提供一致的方式來傳送事件。 物件可以使用事件來發出非同步方法完成的訊號,或通知應用程式有關物件狀態的變更。
如果物件傳送事件,則會公開 IMFMediaEventGenerator 介面。 每當物件傳送新的事件時,事件就會放在佇列中。 應用程式可以呼叫下列其中一種方法,從佇列要求下一個事件:
GetEvent方法是同步的。 如果事件已經在佇列中,方法會立即傳回。 如果佇列中沒有任何事件,方法會立即失敗,或封鎖直到下一個事件排入佇列為止,視您傳入 GetEvent的旗標而定。
BeginGetEvent方法是非同步,因此永遠不會封鎖。 這個方法會採用應用程式必須實作之 IMFAsyncCallback 介面的指標。 叫用回呼時,應用程式會呼叫 IMFMediaEventGenerator::EndGetEvent 以從佇列取得事件。 如需 IMFAsyncCallback的詳細資訊,請參閱 非同步回呼方法。
事件是由 IMFMediaEvent 介面表示。 此介面具有下列方法:
GetType:擷取事件種類。 事件種類表示觸發事件時發生的情況。
GetStatus:擷取 HRESULT 值,指出觸發事件的作業是否成功。 如果作業以非同步方式失敗, GetStatus 會傳回失敗碼。
GetValue:擷取包含事件資料的 PROPVARIANT 。 事件資料取決於事件種類。 某些事件沒有任何資料。
GetExtendedType:擷取 GUID。 此方法適用于 MEExtendedType 事件,並提供定義自訂事件的方式。
IMFMediaEvent介面也會繼承IMFAttributes介面。 某些事件會以屬性的形式提供其他資訊。
如需事件種類及其相關資料和屬性的清單,請參閱 媒體基礎事件。
實作 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);
}
};
相關主題