Step 6: Control Playback

This topic is step 6 of the tutorial How to Play Media Files with Media Foundation. The complete code is shown in the topic Media Session Playback Example.

This topic contains the following sections:

Starting Playback

To start playback, call IMFMediaSession::Start. The following code shows how to start from the current playback position.

//  Start playback from the current position. 
HRESULT CPlayer::StartPlayback()
{
    assert(m_pSession != NULL);

    PROPVARIANT varStart;
    PropVariantInit(&varStart);

    HRESULT hr = m_pSession->Start(&GUID_NULL, &varStart);
    if (SUCCEEDED(hr))
    {
        // Note: Start is an asynchronous operation. However, we
        // can treat our state as being already started. If Start
        // fails later, we'll get an MESessionStarted event with
        // an error code, and we will update our state then.
        m_state = Started;
    }
    PropVariantClear(&varStart);
    return hr;
}

//  Start playback from paused or stopped.
HRESULT CPlayer::Play()
{
    if (m_state != Paused && m_state != Stopped)
    {
        return MF_E_INVALIDREQUEST;
    }
    if (m_pSession == NULL || m_pSource == NULL)
    {
        return E_UNEXPECTED;
    }
    return StartPlayback();
}

The Start method can also specify a starting position relative to the start of the file; see the API reference topic for more information.

Pausing Playback

To pause playback, call IMFMediaSession::Pause.

//  Pause playback.
HRESULT CPlayer::Pause()    
{
    if (m_state != Started)
    {
        return MF_E_INVALIDREQUEST;
    }
    if (m_pSession == NULL || m_pSource == NULL)
    {
        return E_UNEXPECTED;
    }

    HRESULT hr = m_pSession->Pause();
    if (SUCCEEDED(hr))
    {
        m_state = Paused;
    }

    return hr;
}

Stopping Playback

To stop playback, call IMFMediaSession::Stop. While playback is stopped, the video image is cleared and the video window is painted with the background color (black by default).

// Stop playback.
HRESULT CPlayer::Stop()
{
    if (m_state != Started && m_state != Paused)
    {
        return MF_E_INVALIDREQUEST;
    }
    if (m_pSession == NULL)
    {
        return E_UNEXPECTED;
    }

    HRESULT hr = m_pSession->Stop();
    if (SUCCEEDED(hr))
    {
        m_state = Stopped;
    }
    return hr;
}

Repainting the Video Window

The Enhanced Video Renderer (EVR) draws the video in the window specified by the application. This occurs on a separate thread, and for the most part, your application does not need to manage this process. If playback is paused or stopped, however, the EVR must be notified whenever the video window receives a WM_PAINT message. This allows the EVR to repaint the window. To notify the EVR, call the IMFVideoDisplayControl::RepaintVideo method:

//  Repaint the video window. Call this method on WM_PAINT.

HRESULT CPlayer::Repaint()
{
    if (m_pVideoDisplay)
    {
        return m_pVideoDisplay->RepaintVideo();
    }
    else
    {
        return S_OK;
    }
}

The following code shows the handler for the WM_PAINT message. This function should be called from the application's message loop.

//  Handler for WM_PAINT messages.
void OnPaint(HWND hwnd)
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hwnd, &ps);

    if (g_pPlayer && g_pPlayer->HasVideo())
    {
        // Video is playing. Ask the player to repaint.
        g_pPlayer->Repaint();
    }
    else
    {
        // The video is not playing, so we must paint the application window.
        RECT rc;
        GetClientRect(hwnd, &rc);
        FillRect(hdc, &rc, (HBRUSH) COLOR_WINDOW);
    }
    EndPaint(hwnd, &ps);
}

The HasVideo method returns TRUE if the CPlayer object has a valid IMFVideoDisplayControl pointer. (See Step 1: Declare the CPlayer Class.)

    BOOL          HasVideo() const { return (m_pVideoDisplay != NULL);  }

Resizing the Video Window

If you resize the video window, update the destination rectangle on the EVR by calling the IMFVideoDisplayControl::SetVideoPosition method:

//  Resize the video rectangle.
//
//  Call this method if the size of the video window changes.

HRESULT CPlayer::ResizeVideo(WORD width, WORD height)
{
    if (m_pVideoDisplay)
    {
        // Set the destination rectangle.
        // Leave the default source rectangle (0,0,1,1).

        RECT rcDest = { 0, 0, width, height };

        return m_pVideoDisplay->SetVideoPosition(NULL, &rcDest);
    }
    else
    {
        return S_OK;
    }
}

Next: Step 7: Shut Down the Media Session

Audio/Video Playback

How to Play Media Files with Media Foundation