步骤 6:控制播放

本主题是教程的第 6 步 :如何使用 Media Foundation 播放媒体文件。 完整的代码显示在主题 媒体会话播放示例中。

本主题包含以下各节:

开始播放

若要开始播放,请调用 IMFMediaSession::"开始"菜单。 以下代码演示如何从当前播放位置开始。

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

"开始"菜单方法还可以指定相对于文件开头的起始位置;有关详细信息,请参阅 API 参考主题。

暂停播放

若要暂停播放,请调用 IMFMediaSession::P ause

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

停止播放

若要停止播放,请调用 IMFMediaSession::Stop。 当播放停止时,将清除视频图像,并且默认使用背景色 (黑色绘制视频窗口) 。

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

重新绘制视频窗口

增强的视频呈现器 (EVR) 在应用程序指定的窗口中绘制视频。 这发生在单独的线程上,在大多数情况下,应用程序不需要管理此过程。 但是,如果播放已暂停或停止,则每当视频窗口收到 WM_PAINT 消息时,都必须通知 EVR。 这允许 EVR 重新绘制窗口。 若要通知 EVR,请调用 IMFVideoDisplayControl::RepaintVideo 方法:

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

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

以下代码显示 WM_PAINT 消息的处理程序。 应从应用程序的消息循环调用此函数。

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

如果CPlayer对象具有有效的 IMFVideoDisplayControl 指针,该方法HasVideo将返回 TRUE。 (请参阅 步骤 1:声明 CPlayer Class.)

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

调整视频窗口的大小

如果调整视频窗口的大小,请通过调用 IMFVideoDisplayControl::SetVideoPosition 方法更新 EVR 上的目标矩形:

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

一步:步骤 7:关闭媒体会话

音频/视频播放

如何使用 Media Foundation 播放媒体文件