共用方式為


開始使用 MFPlay

[MFPlay 可用於需求一節中指定的作業系統。 後續版本可能會變更或無法使用。 ]

MFPlay 是一種 API,可用於在 C++ 中建立媒體播放應用程式。

本主題包含下列幾節:

需求

MFPlay 需要 Windows 7。

關於 MFPlay

MFPlay 具有簡單的程序設計模型,同時提供大部分播放應用程式所需的核心功能集。 應用程式會 建立可控制播放的播放 程序物件。 若要播放媒體檔案,播放器物件會 建立媒體專案,可用來取得媒體檔案內容的相關信息。 應用程式會透過播放程式物件 IMFPMediaPlayer 介面上的方法控制播放。 或者,應用程式可以透過回呼介面取得事件通知。下圖說明此程式。

conceptual diagram: application and player point to each other, both point to media item, which points to media file

播放媒體檔案

若要播放媒體檔案,請呼叫 MFPCreateMediaPlayer 函 式。

// Global variables
IMFPMediaPlayer *g_pPlayer = NULL;

const WCHAR *sURL = L"C:\\Users\\Public\\Videos\\example.wmv";

HRESULT PlayVideo(HWND hwnd, const WCHAR* sURL)
{
    // Create the player object and play a video file.

    return MFPCreateMediaPlayer(
        sURL,
        TRUE,   // Start playback automatically?
        0,      // Flags.
        NULL,   // Callback pointer.
        hwnd,
        &g_pPlayer
        );
}

MFPCreateMediaPlayer 函式會建立 MFPlay player 物件的新實例。 函式會採用下列參數:

  • 第一個參數是要開啟之檔案的URL。 這可以是本機檔案或媒體伺服器上的檔案。
  • 第二個參數會指定是否自動開始播放。 將此參數設定為 TRUE,檔案會在 MFPlay 載入它時立即播放。
  • 第三個參數會設定各種選項。 針對預設選項,傳遞零 (0)。
  • 第四個參數是選擇性回呼介面的指標。 此參數可以是 NULL,如下所示。 回呼會在接收來自播放機的事件一節中說明。
  • 第五個參數是應用程式視窗的句柄。 如果媒體檔案包含視訊串流,則影片會出現在此視窗的工作區內。 針對僅限音訊播放,此參數可以是 NULL

最後一個參數會接收玩家物件的 IMFPMediaPlayer 介面指標。

在應用程式關閉之前,請務必釋放 IMFPMediaPlayer 指標。 您可以在WM_CLOSE訊息處理程式中執行此動作。

void OnClose(HWND /*hwnd*/)
{
    SafeRelease(&g_pPlayer);
    SafeRelease(&g_pPlayerCB);
    PostQuitMessage(0);
}

注意

此範例會使用 保管庫 Release 函式來釋放介面指標。

 

針對簡單的視訊播放,這就是您需要的所有程序代碼。 本教學課程的其餘部分將示範如何新增更多功能,從如何控制播放開始。

控制播放

上一節中顯示的程式代碼將會播放媒體檔案,直到到達檔案結尾為止。 您可以在 IMFPMediaPlayer 介面上呼叫下列方法,以停止並開始播放:

當您按下 SPACEBAR時,下列程式代碼會暫停或繼續播放。

//-------------------------------------------------------------------
// OnKeyDown
//
// Handles the WM_KEYDOWN message.
//-------------------------------------------------------------------

void OnKeyDown(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags)
{
    HRESULT hr = S_OK;

    switch (vk)
    {
    case VK_SPACE:

        // Toggle between playback and paused/stopped.
        if (g_pPlayer)
        {
            MFP_MEDIAPLAYER_STATE state = MFP_MEDIAPLAYER_STATE_EMPTY;
            
            g_pPlayer->GetState(&state);

            if (state == MFP_MEDIAPLAYER_STATE_PAUSED ||  
                state == MFP_MEDIAPLAYER_STATE_STOPPED)
            {
                g_pPlayer->Play();
            }
            else if (state == MFP_MEDIAPLAYER_STATE_PLAYING)
            {
                g_pPlayer->Pause();
            }
        }
        break;
    }
}

此範例會呼叫 IMFPMediaPlayer::GetState 方法來取得目前的播放狀態(已暫停、停止或播放),並據以暫停或繼續。

從播放機接收事件

MFPlay 會使用回呼介面將事件傳送至您的應用程式。 此回呼有兩個原因:

  • 播放會在個別的線程上發生。 在播放期間,可能會發生特定事件,例如到達檔案的結尾。 MFPlay 會使用回呼來通知您的應用程式事件。
  • 許多 IMFPMediaPlayer 方法都是異步的,這表示它們會在作業完成之前傳回。 異步方法可讓您從UI線程啟動作業,這可能需要很長的時間才能完成,而不會造成UI封鎖。 作業完成之後,MFPlay 會發出回呼訊號。

若要接收回呼通知,請實作 IMFPMediaPlayerCallback 介面。 此介面會繼承 IUnknown,並定義單一方法 OnMediaPlayerEvent。 若要設定回呼,請在 MFPCreateMediaPlayer 函式的 pCallback 參數中傳遞 IMFPMediaPlayerCallback 實作的指標

以下是本教學課程的第一個範例,已修改為包含回呼。

// Global variables.
IMFPMediaPlayer *g_pPlayer = NULL;
IMFPMediaPlayerCallback *g_pCallback = NULL;

// Call an application-defined function to create the callback object.
hr = CreateMyCallback(&g_pCallback);

// Create the player object and play a video file.

const WCHAR *sURL = L"C:\\Users\\Public\\Videos\\example.wmv";

if (SUCCEEDED(hr))
{
    hr = MFPCreateMediaPlayer(
        sURL,
        TRUE,        // Start playback automatically?
        0,           // Flags.
        g_pCallback, // Callback pointer.
        hwnd,
        &g_pPlayer
        );
}

OnMediaPlayerEvent 方法具有單一參數,這是MFP_EVENT_HEADER結構的指標 此結構的 eEventType 成員會告訴您發生哪一個事件。 例如,播放開始時,MFPlay 會傳送 MFP_EVENT_TYPE_PLAY 事件。

每個事件類型都有對應的數據結構,其中包含該事件的資訊。 每個結構都是以 MFP_EVENT_HEADER 結構開頭。 在您的回呼中,將 MFP_EVENT_HEADER 指標轉換成事件特定的數據結構。 例如,如果事件類型是MFP_PLAY_EVENT,則數據結構會MFP_PLAY_EVENT 下列程式代碼示範如何在回呼中處理此事件。

void STDMETHODCALLTYPE MediaPlayerCallback::OnMediaPlayerEvent(
    MFP_EVENT_HEADER *pEventHeader
    )
{
    switch (pEventHeader->eEventType)
    {
    case MFP_EVENT_TYPE_PLAY:
        OnPlay(MFP_GET_PLAY_EVENT(pEventHeader));
        break;

    // Other event types (not shown).

    }
}

// Function to handle the event.
void OnPlay(MFP_PLAY_EVENT *pEvent)
{
    if (FAILED(pEvent->header.hrEvent))
    {  
        // Error occurred during playback.
    }  
}

這個範例會使用 MFP_GET_PLAY_EVENT 事件,將 pEventHeader 指標轉換成MFP_PLAY_EVENT結構。 觸發事件的作業 HRESULT 會儲存在 結構的 hrEvent 字段中。

如需所有事件類型和對應數據結構的清單,請參閱 MFP_EVENT_TYPE

線程的相關注意事項:根據預設,MFPlay 會從稱為 MFPCreateMediaPlayer 的相同線程叫用回呼。 此線程必須有訊息迴圈。 或者,您可以在 MFPCreateMediaPlayercreationOptions 參數中傳遞MFP_OPTION_FREE_THREADED_CALLBACK旗標。 此旗標會導致 MFPlay 從個別線程叫用回呼。 任一選項對您的應用程式都有影響。 默認選項表示回呼無法執行任何在訊息迴圈上等候的任何動作,例如等候UI動作,因為這將會封鎖視窗程式。 自由線程選項表示您必須使用重要區段來保護您在回呼中存取的任何數據。 在大部分情況下,預設選項最簡單。

取得媒體檔案的相關信息

當您在 MFPlay 中開啟媒體檔案時,播放機會建立稱為 媒體項目的 物件,代表媒體檔案。 此物件會 公開IMFPMediaItem 介面,您可以使用該介面來取得媒體檔案的相關信息。 許多 MFPlay 事件結構都包含目前媒體專案的指標。 您也可以在播放機上呼叫 IMFPMediaPlayer::GetMediaItem 來取得目前的媒體專案。

IMFPMediaItem::HasVideo IMFPMediaItem::HasAudio 有兩個特別有用的方法。 這些方法會查詢媒體來源是否包含視訊或音訊。

例如,下列程式代碼會測試目前的媒體檔案是否包含視訊數據流。

IMFPMediaItem *pItem;
BOOL bHasVideo = FALSE;
BOOL bIsSelected = FALSE;

hr = g_pPlayer->GetMediaItem(TRUE, &pItem);
if (SUCCEEDED(hr))
{
    hr = pItem->HasVideo(&bHasVideo, &bIsSelected);
    pItem->Release();
}

如果來源檔案包含選取播放的視訊串流,bHasVideobIsSelected 都會設定為 TRUE

管理視訊播放

當 MFPlay 播放視訊檔案時,它會在 MFPCreateMediaPlayer 函式中指定的視窗中繪製影片。 這會發生在 Microsoft Media Foundation 播放管線所擁有的個別線程上。 在大多數情況下,您的應用程式不需要管理此程式。 不過,應用程式必須通知 MFPlay 更新影片的情況有兩種。

  • 如果播放已暫停或停止,則每當應用程式視訊視窗收到WM_PAINT訊息時,就必須通知 MFPlay。 這可讓 MFPlay 重新繪出視窗。
  • 如果視窗重設大小,則必須通知 MFPlay,才能調整視訊以符合新的視窗大小。

IMFPMediaPlayer::UpdateVideo 方法會處理這兩個案例。 在視訊視窗的WM_PAINT和WM_SIZE訊息處理程式內呼叫這個方法。

重要

呼叫 UpdateVideo 之前,請先呼叫 GDI Begin 小畫家 函式。

 

IMFPMediaPlayer *g_pPlayer;   // MFPlay player object

void OnSize(HWND hwnd, UINT state, int cx, int cy)
{
    HDC hdc;
    PAINTSTRUCT ps;

    if (g_pPlayer && (state == SIZE_RESTORED))
    {
        hdc = BeginPaint(hwnd, &ps);
        g_pPlayer->UpdateVideo();
         EndPaint(hwnd, &ps);
    }
}

void OnPaint(HWND hwnd)
{
    HDC hdc;
    PAINTSTRUCT ps;

    hdc = BeginPaint(hwnd, &ps);
    if (g_pPlayer)
    {
        g_pPlayer->UpdateVideo();
    }
      EndPaint(hwnd, &ps);
}

除非您另有指定,否則 MFPlay 會視需要使用信箱處理,以正確的外觀比例顯示影片。 如果您不想保留外觀比例,請使用 MFVideoARMode_None 旗標呼叫 IMFPMediaPlayer::SetAspectRatioMode 這會導致 MFPlay 延展視訊以填滿整個矩形,而沒有信箱。 一般而言,您應該使用預設設定,並讓 MFPlay 寄信箱播放影片。 默認的信箱色彩為黑色,但您可以呼叫 IMFPMediaPlayer::SetBorderColor 來變更此色彩。

MFPlay 的限制

目前的 MFPlay 版本有下列限制:

  • MFPlay 不支援受DRM保護的內容。
  • 根據預設,MFPlay 不支援網路串流通訊協定。 如需詳細資訊,請參閱 IMFPMediaPlayer::CreateMediaItemFromURL
  • MFPlay 不支援伺服器端播放清單 (SSPLs) 或播放多個區段的其他來源類型。 就技術而言,MFPlay 會在第一次簡報之後停止播放,並忽略來自媒體來源的任何 MENewPresentation 事件。
  • MFPlay 不支援媒體來源之間的無縫轉換。
  • MFPlay 不支援混合多個視訊串流。
  • MFPlay 僅支援媒體基礎中原生支持的媒體格式。 (這包括可能安裝在系統上的第三方媒體基礎元件。

使用 MFPlay 進行音訊/視訊播放