メディア イベント ジェネレーター

Media Foundation は、オブジェクトがイベントを送信するための一貫した方法を提供します。 オブジェクトは、イベントを使用して非同期メソッドの完了を通知したり、オブジェクトの状態の変更についてアプリケーションに通知したりできます。

オブジェクトがイベントを送信すると、 IMFMediaEventGenerator インターフェイスが公開されます。 オブジェクトが新しいイベントを送信するたびに、イベントはキューに配置されます。 アプリケーションは、次のいずれかのメソッドを呼び出すことによって、キューから次のイベントを要求できます。

GetEvent メソッドは同期です。 イベントが既にキュー内にある場合、メソッドは直ちに を返します。 キューにイベントがない場合、メソッドはすぐに失敗するか、 GetEvent に渡すフラグに応じて、次のイベントがキューに登録されるまでブロックします。

BeginGetEvent メソッドは非同期であるため、ブロックされません。 このメソッドは、アプリケーションが実装する必要がある IMFAsyncCallback インターフェイスへのポインターを受け取ります。 コールバックが呼び出されると、アプリケーションは IMFMediaEventGenerator::EndGetEvent を呼び出してキューからイベントを取得します。 IMFAsyncCallback の詳細については、「非同期コールバック メソッド」を参照してください。

イベントは、 IMFMediaEvent インターフェイスによって表されます。 このインターフェイスには、次のメソッドがあります。

  • GetType: イベントの種類を取得します。 イベントの種類は、イベントをトリガーするために何が発生したかを示します。

  • GetStatus: イベントをトリガーした操作が成功したかどうかを示す HRESULT 値を取得します。 操作が非同期的に失敗した場合、 GetStatus はエラー コードを返します。

  • GetValue: イベント データを含む PROPVARIANT を取得します。 イベント データは、イベントの種類によって異なります。 一部のイベントにはデータがありません。

  • GetExtendedType: GUID を取得します。 このメソッドは MEExtendedType イベントに適用され、カスタム イベントを定義する方法を提供します。

IMFMediaEvent インターフェイスは、IMFAttributes インターフェイスも継承します。 一部のイベントでは、属性として追加情報が保持されます。

イベントの種類とその関連するデータと属性の一覧については、「 Media Foundation イベント」を参照してください。

IMFMediaEventGenerator の実装

カスタム メディア ソースやメディア シンクなど、Media Foundation 用のプラグイン コンポーネントを作成する場合は、 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