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(PCWSTR sURL);
    HRESULT       Play();
    HRESULT       Pause();
    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();
    HRESULT CreateMediaSource(PCWSTR sURL);
    HRESULT CreateTopologyFromSource(IMFTopology **ppTopology);

    HRESULT AddBranchToPartialTopology(
        IMFTopology *pTopology,
        IMFPresentationDescriptor *pSourcePD,
        DWORD iStream
        );

    // Media event handlers
    HRESULT OnTopologyReady(IMFMediaEvent *pEvent);
    HRESULT OnPresentationEnded(IMFMediaEvent *pEvent);

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