Étape 1 : Déclarer la classe CPlayer

Cette rubrique est l’étape 1 du tutoriel Guide pratique pour lire des fichiers multimédias avec Media Foundation. Le code complet est affiché dans la rubrique Media Session Playback Example.

Dans ce didacticiel, la fonctionnalité de lecture est encapsulée dans la CPlayer classe. La classe CPlayer est déclarée comme suit :

const UINT WM_APP_PLAYER_EVENT = WM_APP + 1;   

    // WPARAM = IMFMediaEvent*, WPARAM = MediaEventType

enum PlayerState
{
    Closed = 0,     // No session.
    Ready,          // Session was created, ready to open a file. 
    OpenPending,    // Session is opening a file.
    Started,        // Session is playing a file.
    Paused,         // Session is paused.
    Stopped,        // Session is stopped (ready to play). 
    Closing         // Application has closed the session, but is waiting for MESessionClosed.
};

class CPlayer : public IMFAsyncCallback
{
public:
    static HRESULT CreateInstance(HWND hVideo, HWND hEvent, CPlayer **ppPlayer);

    // IUnknown methods
    STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
    STDMETHODIMP_(ULONG) AddRef();
    STDMETHODIMP_(ULONG) Release();

    // IMFAsyncCallback methods
    STDMETHODIMP  GetParameters(DWORD*, DWORD*)
    {
        // Implementation of this method is optional.
        return E_NOTIMPL;
    }
    STDMETHODIMP  Invoke(IMFAsyncResult* pAsyncResult);

    // Playback
    HRESULT       OpenURL(const WCHAR *sURL);
    HRESULT       Play();
    HRESULT       Pause();
    HRESULT       Stop();
    HRESULT       Shutdown();
    HRESULT       HandleEvent(UINT_PTR pUnkPtr);
    PlayerState   GetState() const { return m_state; }

    // Video functionality
    HRESULT       Repaint();
    HRESULT       ResizeVideo(WORD width, WORD height);
    
    BOOL          HasVideo() const { return (m_pVideoDisplay != NULL);  }

protected:
    
    // Constructor is private. Use static CreateInstance method to instantiate.
    CPlayer(HWND hVideo, HWND hEvent);

    // Destructor is private. Caller should call Release.
    virtual ~CPlayer(); 

    HRESULT Initialize();
    HRESULT CreateSession();
    HRESULT CloseSession();
    HRESULT StartPlayback();

    // Media event handlers
    virtual HRESULT OnTopologyStatus(IMFMediaEvent *pEvent);
    virtual HRESULT OnPresentationEnded(IMFMediaEvent *pEvent);
    virtual HRESULT OnNewPresentation(IMFMediaEvent *pEvent);

    // Override to handle additional session events.
    virtual HRESULT OnSessionEvent(IMFMediaEvent*, MediaEventType) 
    { 
        return S_OK; 
    }

protected:
    long                    m_nRefCount;        // Reference count.

    IMFMediaSession         *m_pSession;
    IMFMediaSource          *m_pSource;
    IMFVideoDisplayControl  *m_pVideoDisplay;

    HWND                    m_hwndVideo;        // Video window.
    HWND                    m_hwndEvent;        // App window to receive events.
    PlayerState             m_state;            // Current state of the media session.
    HANDLE                  m_hCloseEvent;      // Event to wait on while closing.
};

Voici quelques points à noter sur CPlayer:

  • La constante WM_APP_PLAYER_EVENT définit un message de fenêtre privée. Ce message est utilisé pour avertir l’application des événements de session multimédia. Consultez l’étape 5 : Gérer les événements de session multimédia.
  • L’énumération PlayerState définit les états possibles de l’objet CPlayer .
  • La CPlayer classe implémente l’interface IMFAsyncCallback , qui est utilisée pour obtenir des notifications d’événements à partir de la session multimédia.
  • Le CPlayer constructeur est privé. L’application appelle la méthode statique CreateInstance pour créer une instance de la CPlayer classe.
  • Le CPlayer destructeur est également privé. La CPlayer classe implémente IUnknown, de sorte que la durée de vie de l’objet est contrôlée par le biais de son nombre de références (m_nRefCount). Pour détruire l’objet, l’application appelle IUnknown::Release, et non la suppression.
  • L’objet CPlayer gère à la fois la session multimédia et la source multimédia.

Implémenter IUnknown

La CPlayer classe implémente IMFAsyncCallback, qui hérite d’IUnknown.

Le code présenté ici est une implémentation assez standard d’IUnknown. Si vous préférez, vous pouvez utiliser la bibliothèque de modèles active (ATL) pour implémenter ces méthodes. Toutefois, CPlayer ne prend pas en charge CoCreateInstance ni les fonctionnalités COM avancées, il n’y a donc aucune raison écrasante d’utiliser ATL ici.

HRESULT CPlayer::QueryInterface(REFIID riid, void** ppv)
{
    static const QITAB qit[] = 
    {
        QITABENT(CPlayer, IMFAsyncCallback),
        { 0 }
    };
    return QISearch(this, qit, riid, ppv);
}

ULONG CPlayer::AddRef()
{
    return InterlockedIncrement(&m_nRefCount);
}

ULONG CPlayer::Release()
{
    ULONG uCount = InterlockedDecrement(&m_nRefCount);
    if (uCount == 0)
    {
        delete this;
    }
    return uCount;
}

Suivant : Étape 2 : Créer l’objet CPlayer

Lecture audio/vidéo

Guide pratique pour lire des fichiers multimédias avec Media Foundation