媒体播放器

媒体播放涉及通过内联(嵌入在页面中或使用一组其他控件)或专用全屏体验来观看和收听视频和音频。

用户需要一个基本控制集(如播放/暂停、快退、快进),你可以根据需要进行修改(包括媒体播放器的按钮、控件条的背景以及控件排列或布局)。

媒体播放器元素的屏幕截图,其中传输控件播放了一个女士虫的视频

这是正确的控件吗?

在应用中播放音频或视频时,请使用媒体播放器。 若要显示图像集合,请使用 翻转视图

建议

媒体播放器支持浅色和深色主题,但深色主题为大多数娱乐场景提供了更好的体验。 深色背景提供更好的对比度,特别是对于低光条件,并限制控制栏干扰观看体验。

播放视频内容时,通过通过内联模式提升全屏模式来鼓励专门的观看体验。 全屏查看体验是最佳的,并且选项在内联模式下受到限制。

如果你有屏幕空间,请使用双行布局。 它为控件提供了比压缩的单行布局更多的空间,并且更易于使用各种输入进行导航。

默认控件已针对媒体播放进行了优化,但你可以向媒体播放器添加所需的自定义选项,以便为应用提供最佳体验。 访问 “创建自定义传输控件 ”,详细了解如何添加自定义控件。

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 对象并将源设置为指向音频或视频文件的 MediaSource,将媒体添加到应用。

此 XAML 创建 MediaPlayerElement 并将其 Source 属性设置为应用本地视频文件的 URI。 页面 MediaPlayerElement 加载时开始播放。 若要立即禁止媒体启动,可以将“自动播放”属性设置为 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 类引用和创建自定义传输控件

传输控件支持单行和双行布局。 此处的第一个示例是单行布局,其中播放/暂停按钮位于媒体时间线左侧。 此布局最适合用于内联媒体播放和紧凑屏幕。

MTC 控件示例,单行

对于大多数使用方案(尤其是较大的屏幕),建议使用双行控件布局(如下所示)。 此布局为控件提供更多空间,使用户能够更轻松地操作日程表。

双行 MTC 控件示例

系统媒体传输控件

MediaPlayerElement 自动与系统媒体传输控件集成。 系统媒体传输控件是按下硬件媒体键时弹出的控件,例如键盘上的媒体按钮。 有关详细信息,请参阅 SystemMediaTransportControls

设置媒体源

若要在嵌入应用的网络或文件中播放文件,请将 Source 属性设置为具有文件路径的 MediaSource

提示

若要从 Internet 打开文件,需要在应用的清单(Package.appxmanifest)中声明 Internet(客户端) 功能。 有关声明功能的详细信息,请参阅应用功能声明

此代码尝试将使用 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,然后将源设置为 Uri。 例如,对于名为“视频”子文件夹中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 获取文件和 来设置媒体源,也可以以编程方式访问用户媒体文件夹。

例如,如果你的应用需要访问而无需用户与音乐或视频文件夹交互,例如,如果要枚举用户集合中的所有音乐或视频文件并在应用中显示它们,则需要声明音乐库视频库功能。 有关详细信息,请参阅音乐、图片和视频库中的文件和文件夹

FileOpenPicker 不需要特殊功能即可访问本地文件系统上的文件(例如用户的音乐视频文件夹),因为用户对所访问的文件具有完全控制权。 从安全和隐私的角度来看,最好尽量减少应用使用的功能数量。

使用 FileOpenPicker 打开本地媒体

  1. 调用 FileOpenPicker 以允许用户选取媒体文件。

    使用 FileOpenPicker 类选择媒体文件。 设置 FileTypeFilter 以指定显示的文件类型 FileOpenPicker 。 调用 PickSingleFileAsync 以启动文件选取器并获取文件。

  2. 使用 MediaSource 将所选媒体文件设置为 MediaPlayerElement.Source

    若要使用 FileOpenPicker 返回的 StorageFile,需要在 MediaSource调用 CreateFromStorageFile 方法,并将其设置为 MediaPlayerElement源。 然后对 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已设置为null或源无效(如发生 MediaFailed 事件时的情况)。
  • 正在加载媒体时。 例如,设置了有效的源,但 尚未发生 MediaOpened 事件。
  • 当媒体流式传输到另一台设备时。
  • 仅当媒体为音频时。

下面是一个 MediaPlayerElement ,其 Source 设置为专辑曲目,并将 PosterSource 设置为专辑封面的图像。

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

使设备的屏幕保持活动状态

通常,设备会将显示器变暗(并最终关闭),以便在用户离开时节省电池使用时间,但视频应用需要保持屏幕,以便用户能够看到视频。 若要防止在不再检测到用户操作时停用显示,例如当应用正在播放视频时,可以调用 DisplayRequest.RequestActive。 DisplayRequest 类允许你告诉 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 状态类似于许多电视机上的图片大小设置。 你可以将此关联到按钮,并允许用户选择他们喜欢的设置。

  • 一项以原始大小显示内容的本机分辨率。这可能会导致视频边缘裁剪或黑条。
  • 一填充尽可能多的空间,同时保留纵横比和视频内容。 这可能会导致视频边缘的水平或垂直黑条。 这类似于宽屏模式。
  • UniformToFill 会 填充整个空间,同时保留纵横比。 这可能会导致一些视频被裁剪。 这类似于全屏模式。
  • 填充 整个空间,但不保留纵横比。 不会裁剪任何视频,但可能会进行拉伸。 这类似于拉伸模式。

拉伸枚举值

在这里, 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;
    }
}

启用低延迟播放

RealTimePlayback 属性设置为 true MediaPlayerElement.MediaPlayer ,使媒体播放器元素能够减少播放的初始延迟。 这对于双向通信应用至关重要,适用于某些游戏方案。 请注意,此模式的资源密集型程度更高,电源效率更低。

此示例创建 MediaPlayerElement 并将 RealTimePlayback 设置为 true

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