Step 1: Declare the CPlayer Class
This topic is step 1 of the tutorial How to Play Media Files with Media Foundation. The complete code is shown in the topic Media Session Playback Example.
In this tutorial, playback functionality is encapsulated in the CPlayer
class. The CPlayer
class is declared as follows:
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.
};
Here are some things to note about CPlayer
:
- The constant WM_APP_PLAYER_EVENT defines a private window message. This message is used to notify the application about Media Session events. See Step 5: Handle Media Session Events.
- The
PlayerState
enumeration defines the possible states of theCPlayer
object. - The
CPlayer
class implements the IMFAsyncCallback interface, which is used to get event notifications from the Media Session. - The
CPlayer
constructor is private. The application calls the staticCreateInstance
method to create an instance of theCPlayer
class. - The
CPlayer
destructor is also private. TheCPlayer
class implements IUnknown, so the object's lifetime is controlled through its reference count (m_nRefCount). To destroy the object, the application calls IUnknown::Release, not delete. - The
CPlayer
object manages both the Media Session and the media source.
Implement IUnknown
The CPlayer
class implements IMFAsyncCallback, which inherits IUnknown.
The code shown here is a fairly standard implementation of IUnknown. If you prefer, you can use the Active Template Library (ATL) to implement these methods. However, CPlayer
does not support CoCreateInstance or any advanced COM features, so there is no overwhelming reason to use ATL here.
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;
}
Next: Step 2: Create the CPlayer Object
Related topics