媒體播放器

媒體播放涉及透過內嵌 (內嵌在頁面或包含一組其他控制項) 或專用全螢幕體驗觀看和聆聽影片和音訊。

使用者預期有一組基本的控制項,例如:播放/暫停、向後跳過、向前跳過,您可以視需要修改這些設定 (包括媒體播放器的按鈕、控制列的背景以及控制項排列或或版面配置)。

A screenshot of a media player element with transport controls playing a video of a ladybug

這是正確的控制項嗎?

當您想要在應用程式中播放音訊或影片時,請使用媒體播放器。 若要顯示影像集合,請使用翻轉檢視

建議

媒體播放器同時支援淺色和深色主題,但深色主題為大多數娛樂場景提供更好的體驗。 深色背景可提供更好的對比度,特別是在低光源條件下,並限制控制列干擾觀看體驗。

播放影片內容時,透過提升全螢幕模式而不是內嵌模式來鼓勵專注的觀看體驗。 全螢幕檢視體驗是最佳的,而在內嵌模式下選項受到限制。

如果您有螢幕實際可用空間,請使用雙列版面配置。 與精簡單列版面配置相比,它提供更多的控制項空間,並且可以更輕鬆地使用各種輸入裝置瀏覽。

預設控制項已針對媒體播放進行最佳化,但您可以將需要的自訂選項加入媒體播放程式,以便為您的應用程式提供最佳體驗。 若要深入了解如何新增自訂控制項,請造訪建立自訂傳輸控制項

UWP 和 WinUI 2

重要

本文中的資訊和範例針對使用 Windows App SDKWinUI 3 的應用程式進行了最佳化,但通常適用於使用 WinUI 2 的 UWP 應用程式。 如需平台特定資訊和範例,請參閱 UWP API 參考。

本節包含您在 UWP 或 WinUI 2 應用程式中使用控制項所需的資訊。

此控制項的 API 位在 Windows.UI.Xaml.Controls 命名空間中。

建議使用最新的 WinUI 2 來取得所有控制項的最新樣式和範本。 WinUI 2.2 或更新版本包含此使用圓角之控制項的新範本。 如需詳細資訊,請參閱圓角半徑

如果您要設計 10 英呎體驗,請使用雙列版面配置。 與精簡單列版面配置相比,它提供更多的控制項空間,並且可以更輕鬆地使用遊戲台實現 10 英呎的瀏覽。 如需了解 10 英呎體驗最佳化應用程式的詳細資訊,請參閱Xbox 和電視設計一文。

MediaPlayerElement 僅適用於 Windows 10 版本 1607 和更新版本。 如果您正在為早期版本的 Windows 10 開發應用程式,則需要改用 MediaElement 控制項。 此處提出的所有建議也適用於 MediaElement

建立媒體播放器

WinUI 3 資源庫應用程式包含大多數 WinUI 3 控制項和功能的互動式範例。 從 Microsoft Store 取得應用程式,或在 GitHub 上取得原始程式碼

透過在 XAML 中建立 MediaPlayerElement 物件並將 Source 設定為指向音訊或影片檔案的 MediaSource 來將媒體新增至您的應用程式。

此 XAML 會建立 MediaPlayerElement,並將其 Source 屬性設定為應用程式本機影片檔案的 URI。 會在頁面載入時開始播放 MediaPlayerElement。 若要抑制媒體立即播放,您可以將 AutoPlay 屬性設為 false

<MediaPlayerElement x:Name="mediaPlayerElement"
                    Source="ms-appx:///Videos/video1.mp4"
                    Width="400" AutoPlay="True"/>

此 XAML 會建立已啟用內建傳輸控制項的 MediaPlayerElement,並將 AutoPlay 屬性設定為 false.

<MediaPlayerElement x:Name="mediaPlayerElement"
                    Source="ms-appx:///Videos/video1.mp4"
                    Width="400"
                    AutoPlay="False"
                    AreTransportControlsEnabled="True"/>

重要

MediaPlayerElement.Source 設定為相對 URI (ms-appx/ms-resource) 僅適用於使用 Windows 應用程式封裝專案封裝的應用程式。 如果您的應用程式未使用 Windows 應用程式封裝專案,建議的因應措施是將相對 ms-appx:/// URI 轉換為完全解析的 file:/// URI。 另請參閱本文後段的設定媒體來源開啟本機媒體檔案章節。

媒體傳輸控制項

MediaPlayerElement 具有內建傳輸控制項,可處理播放、停止、暫停、音量、靜音、搜尋/進度、隱藏式輔助字幕及曲目選取。 若要啟用這些控制項,請將 AreTransportControlsEnabled 設定為 true。 若要停用它們,請將 AreTransportControlsEnabled 設定為 false。 傳輸控制項是由 MediaTransportControls 類別表示。 您可以依原樣使用傳輸控制項,或以各種方式自訂它們。 如需詳細資訊,請參閱 MediaTransportControls 類別參考和建立自訂傳輸控制項

傳輸控制項支援單列和雙列版面配置。 這裡的第一個範例是單列版面配置,播放/暫停按鈕位於媒體時間軸左側。 這種版面配置最適合內嵌媒體播放和精簡畫面。

Example of MTC controls, single row

對於大多數使用場景,尤其是在較大的螢幕上,建議使用雙列版面配置 (如下)。 這種版面配置為控制項提供更多空間,並讓使用者更容易操作時間軸。

Example of MTC controls, double row

系統媒體傳輸控制項

MediaPlayerElement 會自動與系統媒體傳輸控制項整合。 系統媒體傳輸控制項是按下硬體媒體鍵 (例如:鍵盤上的媒體按鈕) 時彈出的控制項。 如需詳細資訊,請參閱 SystemMediaTransportControls

設定媒體來源

若要播放位於網路上的檔案或內嵌於 app 的檔案,請將 MediaSourceSource 屬性設定為檔案的路徑。

提示

若要從網際網路開啟檔案,您需要在應用程式資訊清單 (Package.appxmanifest) 中宣告網際網路 (用戶端) 功能。 如需宣告功能的詳細資訊,請參閱應用程式功能宣告

此程式碼會嘗試將 XAML 中定義之 MediaPlayerElementSource 屬性設定為在 TextBox 中輸入的檔案路徑。

<TextBox x:Name="txtFilePath" Width="400"
         FontSize="20"
         KeyUp="TxtFilePath_KeyUp"
         Header="File path"
         PlaceholderText="Enter file path"/>
private void TxtFilePath_KeyUp(object sender, KeyRoutedEventArgs e)
{
    if (e.Key == Windows.System.VirtualKey.Enter)
    {
        TextBox tbPath = sender as TextBox;

        if (tbPath != null)
        {
            LoadMediaFromString(tbPath.Text);
        }
    }
}

private void LoadMediaFromString(string path)
{
    try
    {
        Uri pathUri = new Uri(path);
        mediaPlayerElement.Source = MediaSource.CreateFromUri(pathUri);
    }
    catch (Exception ex)
    {
        if (ex is FormatException)
        {
            // handle exception.
            // For example: Log error or notify user problem with file
        }
    }
}

若要將媒體來源設定為內嵌於應用程式中的媒體檔案,請初始化其路徑開頭為 ms-appx:///Uri,以此 Uri 建立 MediaSource,然後將 Source 設定為該 Uri。 例如,對於位於 Videos 子資料夾中名為 video1.mp4 的檔案,路徑將如下所示:ms-appx:///Videos/video1.mp4

重要

MediaPlayerElement.Source 設定為相對 URI (ms-appx/ms-resource) 僅適用於使用 Windows 應用程式封裝專案封裝的應用程式。

此程式碼會將先前在 XAML 中定義之 MediaPlayerElementSource 屬性設為 ms-appx:///Videos/video1.mp4

private void LoadEmbeddedAppFile()
{
    try
    {
        Uri pathUri = new Uri("ms-appx:///Videos/video1.mp4");
        mediaPlayerElement.Source = MediaSource.CreateFromUri(pathUri);
    }
    catch (Exception ex)
    {
        if (ex is FormatException)
        {
            // handle exception.
            // For example: Log error or notify user problem with file
        }
    }
}

開啟本機媒體檔案

若要開啟本機系統上的檔案,或從 OneDrive 開啟檔案,您可以使用 FileOpenPicker 來取得檔案並使用 Source 來設定媒體來源,也可以以程式設計方式存取使用者媒體資料夾。

如果您的應用程式需要在無需使用者互動的情況下存取音樂影片資料夾,例如,如果您要列舉使用者收藏中的所有音樂或影片檔案並在應用程式中顯示它們,則需要宣告音樂媒體櫃影片庫功能。 如需詳細資訊,請參閱音樂、圖片及影片媒體櫃中的檔案和資料夾

FileOpenPicker 不需要特殊功能來存取本機檔案系統 (例如,使用者的 [音樂] 或 [影片] 資料夾) 上的檔案,因為使用者可以完全控制存取的檔案。 從安全性和隱私權的觀點來看,最好盡量減少應用程式使用的功能數量。

使用 FileOpenPicker 開啟本機媒體

  1. 呼叫 FileOpenPicker 讓使用者挑選媒體檔案。

    使用 FileOpenPicker 類別來選取媒體檔案。 設定 FileTypeFilter,以指定 FileOpenPicker 顯示的檔案類型。 呼叫 PickSingleFileAsync 以啟動檔案選擇器並取得檔案。

  2. 使用 MediaSource 將所選媒體檔案設定為 MediaPlayerElement.Source

    若要使用從 FileOpenPicker 傳回的 StorageFile,您需要呼叫 MediaSource 上的 CreateFromStorageFile 方法,並將它設定為 MediaPlayerElementSource。 接著,請呼叫 MediaPlayerElement.MediaPlayer 上的 Play 來啟動媒體。

這個範例示範如何使用 FileOpenPicker 來選擇檔案,並將該檔案設定為 MediaPlayerElementSource

<MediaPlayerElement x:Name="mediaPlayerElement"/>
...
<Button Content="Choose file" Click="Button_Click"/>
private async void Button_Click(object sender, RoutedEventArgs e)
{
    await SetLocalMedia();
}

async private System.Threading.Tasks.Task SetLocalMedia()
{
    var openPicker = new Windows.Storage.Pickers.FileOpenPicker();
    WinRT.Interop.InitializeWithWindow.Initialize(openPicker, WinRT.Interop.WindowNative.GetWindowHandle(this));

    openPicker.FileTypeFilter.Add(".wmv");
    openPicker.FileTypeFilter.Add(".mp4");
    openPicker.FileTypeFilter.Add(".wma");
    openPicker.FileTypeFilter.Add(".mp3");

    var file = await openPicker.PickSingleFileAsync();

    // mediaPlayerElement is a MediaPlayerElement control defined in XAML
    if (file != null)
    {
        mediaPlayerElement.Source = MediaSource.CreateFromStorageFile(file);

        mediaPlayerElement.MediaPlayer.Play();
    }
}

設定海報來源

可以在載入媒體之前使用 PosterSource 屬性為 MediaPlayerElement 提供視覺化呈現。 PosterSource 是取代媒體顯示的影像,例如:螢幕擷取畫面、電影海報或專輯封面。 會在下列情況下顯示 PosterSource

  • 未設定有效的來源時。 例如,未設定 Source、已將 Source 設定為 null,或來源無效 (如同發生 MediaFailed 事件的情況)。
  • 正在載入媒體時。 例如,已設定有效的來源,但 MediaOpened 事件尚未發生。
  • 當媒體串流傳輸到另一個裝置時。
  • 當媒體只有音訊時。

這是 MediaPlayerElement,其 Source 設定為專輯曲目,其 PosterSource 設定為專輯封面的影像。

<MediaPlayerElement Source="ms-appx:///Media/Track1.mp4" PosterSource="ms-appx:///Media/AlbumCover.png"/>

讓裝置的螢幕保持使用中狀態

通常,裝置會在使用者離開時將顯示器調暗 (並且最終將其關閉) 以節省電池壽命,但影片應用程式需要讓螢幕保持開啟,以便使用者觀看影片。 為了防止在不再偵測到使用者操作時 (例如應用程式正在播放影面時) 停用顯示,可以呼叫 DisplayRequest.RequestActiveDisplayRequest 類別可讓您告訴 Windows 讓顯示器保持開啟狀態,以便使用者可以觀看影片。

為了節省電量和電池壽命,應在不再需要時呼叫 DisplayRequest.RequestRelease 來釋放顯示要求。 當應用程式移離畫面時,Windows 會自動停用應用程式的使用中顯示要求,並在應用程式回到前台時重新啟動這些要求。

以下是一些您應該釋放顯示器要求的情況:

  • 例如,由於使用者操作、緩衝或由於頻寬有限而調整,影片播放會暫停。
  • 播放停止時。 例如,視訊播放完畢或簡報結束。
  • 發生播放錯誤時。 例如,網路連線問題或檔案損毀。

讓螢幕保持使用中

  1. 建立全域 DisplayRequest 變數。 將它初始化為 null

    private DisplayRequest appDisplayRequest = null;
    
  2. 呼叫 RequestActive 以通知 Windows 應用程式要求顯示保持開啟狀態。

  3. 每當影片播放停止、暫停或因播放錯誤而中斷時,呼叫 RequestRelease 釋放顯示要求。 當您的應用程式不再有任何使用中的顯示器要求時,Windows 會在未使用裝置時將顯示器調暗 (並且最終將其關閉) 來節省電池壽命。

每個 MediaPlayerElement.MediaPlayer 都有一個 MediaPlaybackSession 類型 的 PlaybackSession,可控制媒體播放的各種方面,例如 PlaybackRatePlaybackStatePosition。 在這裡,您將使用 MediaPlayer.PlaybackSession 上的 PlaybackStateChanged 事件,來偵測何時應該釋放顯示器要求。 然後,使用 NaturalVideoHeight 屬性來判斷音訊或影片檔案是否正在播放,並且只在播放影片時讓螢幕保持使用中狀態。

<MediaPlayerElement x:Name="mediaPlayerElement" Source="ms-appx:///Videos/video1.mp4"/>
public sealed partial class MainWindow : Window
{
    public DisplayRequest appDisplayRequest = null;
    // using Microsoft.UI.Dispatching;
    private DispatcherQueue dispatcherQueue = DispatcherQueue.GetForCurrentThread();

    public MainWindow()
    {
        this.InitializeComponent();
        mediaPlayerElement.MediaPlayer.PlaybackSession.PlaybackStateChanged += 
            PlaybackSession_PlaybackStateChanged;
    }

    private void PlaybackSession_PlaybackStateChanged(MediaPlaybackSession sender, object args)
    {
        MediaPlaybackSession playbackSession = sender as MediaPlaybackSession;
        if (playbackSession != null && playbackSession.NaturalVideoHeight != 0)
        {
            if (playbackSession.PlaybackState == MediaPlaybackState.Playing)
            {
                if (appDisplayRequest is null)
                {
                    dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Normal, () =>
                    {
                        appDisplayRequest = new DisplayRequest();
                        appDisplayRequest.RequestActive();
                    });
                }
            }
            else // PlaybackState is Buffering, None, Opening, or Paused.
            {
                if (appDisplayRequest is not null)
                {
                    appDisplayRequest.RequestRelease();
                    appDisplayRequest = null;
                }
            }
        }
    }
}

以程式設計方式控制媒體播放器

MediaPlayerElement 提供許多屬性、方法和事件,透過 MediaPlayerElement.MediaPlayer 屬性控制音訊和影片播放。 如需屬性、方法和事件的完整清單,請參閱 MediaPlayer 參考頁面。

進階媒體播放案例

如需更複雜的媒體播放案例,例如:播放播放清單、在音訊語言之間切換,或建立自訂中繼資料軌道,請將 MediaPlayerElement.Source 設定為 MediaPlaybackItemMediaPlaybackList。 如需如何啟用各種進階媒體功能的詳細資訊,請參閱媒體播放頁面。

調整影片大小和拉伸影片

使用 Stretch 屬性來變更影片內容和/或 PosterSource 填入其所在容器的方式。 這會根據 Stretch 值來調整影片大小並拉伸影片。 Stretch 狀態與許多電視機上的圖片尺寸設定類似。 您可以將其連結至按鈕,並允許使用者選擇他們偏好的設定。

  • None 會以原始尺寸顯示內容的原始解析度。這可能會導致部分影片被裁切或影片邊緣出現黑條。
  • Uniform 會盡可能填滿空間,同時保留長寬比和影片內容。 這可能會導致影片邊緣出現水平或垂直黑條。 這與寬螢幕模式類似。
  • UniformToFill 會填滿整個空間,同時保留長寬比。 這可能會導致部分影片被裁剪。 這與全螢幕模式類似。
  • Fill 滿整個空間,但不會保留長寬比。 影片不會被裁剪,但可能會發生拉伸。 這與拉伸模式類似。

Stretch enumeration values

在這裡, AppBarButton 用來循環執行 Stretch 選項。 switch 陳述式會檢查 Stretch 屬性目前的狀態,並將它設定成 Stretch 列舉中的下一個值。 這使得使用者可以在不同的拉伸狀態之間循環。

<AppBarButton Icon="Trim"
              Label="Resize Video"
              Click="PictureSize_Click" />
private void PictureSize_Click(object sender, RoutedEventArgs e)
{
    switch (mediaPlayerElement.Stretch)
    {
        case Stretch.Fill:
            mediaPlayerElement.Stretch = Stretch.None;
            break;
        case Stretch.None:
            mediaPlayerElement.Stretch = Stretch.Uniform;
            break;
        case Stretch.Uniform:
            mediaPlayerElement.Stretch = Stretch.UniformToFill;
            break;
        case Stretch.UniformToFill:
            mediaPlayerElement.Stretch = Stretch.Fill;
            break;
        default:
            break;
    }
}

啟用低延遲播放

MediaPlayerElement.MediaPlayer 上將 RealTimePlayback 屬性設定為 true,以讓媒體播放器元素減少播放的初始延遲。 這對雙向通訊應用程式而言非常重要,而且適用於某些遊戲場景。 請注意,此模式會耗用更多資源,且節能效率較低。

這個範例會建立 MediaPlayerElement,並將 RealTimePlayback 設定為 true

MediaPlayerElement mediaPlayerElement = new MediaPlayerElement();
mediaPlayerElement.MediaPlayer.RealTimePlayback = true;