Bagikan melalui


Generator Peristiwa Media

Media Foundation menyediakan cara yang konsisten bagi objek untuk mengirim peristiwa. Objek dapat menggunakan peristiwa untuk memberi sinyal penyelesaian metode asinkron, atau untuk memberi tahu aplikasi tentang perubahan status objek.

Jika objek mengirim peristiwa, objek akan mengekspos antarmuka IMFMediaEventGenerator . Setiap kali objek mengirim peristiwa baru, peristiwa ditempatkan dalam antrean. Aplikasi dapat meminta peristiwa berikutnya dari antrean dengan memanggil salah satu metode berikut:

Metode GetEvent sinkron. Jika suatu peristiwa sudah berada dalam antrean, metode akan segera kembali. Jika tidak ada peristiwa dalam antrean, metode akan segera gagal, atau memblokir hingga peristiwa berikutnya diantrekan, tergantung pada bendera mana yang Anda berikan ke GetEvent.

Metode BeginGetEvent bersifat asinkron, sehingga tidak pernah memblokir. Metode ini mengambil pointer ke antarmuka IMFAsyncCallback , yang harus diterapkan aplikasi. Ketika panggilan balik dipanggil, aplikasi memanggil IMFMediaEventGenerator::EndGetEvent untuk mendapatkan peristiwa dari antrean. Untuk informasi selengkapnya tentang IMFAsyncCallback, lihat Metode Callback Asinkron.

Peristiwa diwakili oleh antarmuka IMFMediaEvent . Antarmuka ini memiliki metode berikut:

  • GetType: Mengambil jenis peristiwa. Jenis peristiwa menunjukkan apa yang terjadi untuk memicu peristiwa.

  • GetStatus: Mengambil nilai HRESULT , menunjukkan apakah operasi yang memicu peristiwa berhasil. Jika operasi gagal secara asinkron, GetStatus mengembalikan kode kegagalan.

  • GetValue: Mengambil PROPVARIANT yang berisi data peristiwa. Data peristiwa bergantung pada jenis peristiwa. Beberapa peristiwa tidak memiliki data apa pun.

  • GetExtendedType: Mengambil GUID. Metode ini berlaku untuk Peristiwa MEExtendedType, dan menyediakan cara untuk menentukan peristiwa kustom.

Antarmuka IMFMediaEvent juga mewarisi antarmuka IMFAttributes . Beberapa peristiwa membawa informasi tambahan sebagai atribut.

Untuk daftar jenis peristiwa dan data dan atribut terkaitnya, lihat Peristiwa Media Foundation.

Menerapkan IMFMediaEventGenerator

Jika Anda menulis komponen plug-in untuk Media Foundation, seperti sumber media kustom atau sink media, Anda mungkin perlu menerapkan IMFMediaEventGenerator. Untuk mempermudah ini, Media Foundation menyediakan objek pembantu yang mengimplementasikan antrean peristiwa. Buat antrean peristiwa dengan memanggil fungsi MFCreateEventQueue . Antrean peristiwa mengekspos antarmuka IMFMediaEventQueue . Dalam implementasi objek Anda dari metode IMFMediaEventGenerator , panggil metode yang sesuai pada antrean peristiwa.

Objek antrean peristiwa aman untuk utas. Jangan pernah memegang objek bagian penting yang sama saat memanggil GetEvent dan QueueEvent, karena GetEvent mungkin memblokir tanpa batas waktu menunggu QueueEvent. Jika Anda memegang bagian penting yang sama untuk kedua metode, itu akan menyebabkan kebuntuan.

Sebelum merilis antrean peristiwa, panggil IMFMediaEventQueue::Shutdown untuk merilis sumber daya yang dipegang objek.

Saat objek Anda perlu menaikkan peristiwa, panggil salah satu metode berikut pada antrean peristiwa:

Metode ini menempatkan peristiwa baru pada antrean dan memberi sinyal kepada pemanggil apa pun yang menunggu peristiwa berikutnya.

Kode berikut menunjukkan kelas yang mengimplementasikan IMFMediaEventGenerator menggunakan objek pembantu ini. Kelas ini mendefinisikan metode Matikan publik yang mematikan antrean peristiwa dan merilis penunjuk antrean peristiwa. Perilaku ini akan khas untuk sumber media dan sink media, yang selalu memiliki metode Matikan .

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);
    }
};

API Platform Media Foundation