共用方式為


媒體事件產生器

媒體基礎為對象傳送事件提供一致的方式。 物件可以使用事件來發出異步方法完成的訊號,或通知應用程式有關物件狀態的變更。

如果對象傳送事件,則會公開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 方法的 實作中,呼叫事件佇列上的對應方法。

事件佇列物件是安全線程。 呼叫 getEventQueueEvent時,永遠不要保留相同的重要區段對象,因為 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);
    }
};

Media Foundation Platform API