MediaElement

MediaElement 是用于播放视频和音频的控件。 基础平台支持的媒体可以从以下源播放:

  • 使用 URI(HTTP 或 HTTPS)的 Web。
  • 使用 embed:// URI 方案嵌入平台应用程序中的资源。
  • 使用 filesystem:// URI 方案的来自应用的本地文件系统的文件。

MediaElement 可以使用平台播放控件,这些控件称为传输控件。 但是,默认情况下它们处于禁用状态,可以替换为你自己的传输控件。 以下屏幕截图显示 MediaElement 使用平台传输控件播放视频:

在 Android 和 iOS 上播放视频的 MediaElement 的屏幕截图。

注意

MediaElement 可在 iOS、Android、Windows、macOS 和 Tizen 上获取。

MediaElement 使用以下平台实现。

平台 平台媒体播放器实现
Android ExoPlayer,非常感谢 ExoPlayerXamarin 维护者!
iOS/macOS AVPlayer
Windows MediaPlayer

使用入门

若要使用 .NET MAUI Community 工具包的 MediaElement 功能,需要执行以下步骤。

安装 NuGet 包

在应用程序内使用 MediaElement 之前,需要安装 CommunityToolkit.Maui.MediaElement NuGet 包,并在 MauiProgram.cs 中添加初始化行。 如下所示:

包名称CommunityToolkit.Maui.MediaElement

Package url:https://www.nuget.org/packages/CommunityToolkit.Maui.MediaElement

初始化包

首先,需要将 using 语句添加到 MauiProgram.cs 文件的顶部

using CommunityToolkit.Maui.MediaElement;

为了正确使用 MediaElement,必须在启动应用程序 MauiProgram.cs 文件时,对 MauiAppBuilder 类调用 UseMauiCommunityToolkitMediaElement 方法。 以下示例演示如何执行此操作。

var builder = MauiApp.CreateBuilder();
builder
    .UseMauiApp<App>()
    .UseMauiCommunityToolkitMediaElement()

有关如何执行此操作的详细信息,请参阅入门页。

特定于平台的初始化

要访问 MediaElement 功能,需执行以下特定于平台的设置。

使用 MediaElement 时,必须执行以下步骤:

1.将 ResizableActivityLaunchmode 添加到活动

[Activity(Theme = "@style/Maui.SplashTheme", ResizeableActivity = true, MainLauncher = true, LaunchMode = LaunchMode.SingleTask)]
public class MainActivity : MauiAppCompatActivity
{
}

2.将以下内容添加到 <application> 标记内的 AndroidManifest.xml

 <service android:name="communityToolkit.maui.media.services" android:exported="false" android:enabled="true" android:foregroundServiceType="mediaPlayback">
   <intent-filter>
     <action android:name="android.intent.action.MEDIA_BUTTON" />
   </intent-filter>
   <intent-filter>
     <action android:name="androidx.media3.session.MediaSessionService"/>
   </intent-filter>
 </service>

3.将以下权限添加到 AndroidManifest.xml

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />

下面是 AndroidManifest.xml 中所需设置的示例

<application android:allowBackup="true" android:icon="@mipmap/appicon" android:enableOnBackInvokedCallback="true" android:supportsRtl="true">
<service android:name="communityToolkit.maui.media.services" android:exported="false" android:enabled="true" android:foregroundServiceType="mediaPlayback">
    <intent-filter>
    <action android:name="android.intent.action.MEDIA_BUTTON" />
    </intent-filter>
    <intent-filter>
    <action android:name="androidx.media3.session.MediaSessionService"/>
    </intent-filter>
</service>
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />

注意

此对 Android 清单的修改可在播放视频时显示元数据。 它为通知提供支持,对于通知在所有相关 API 中发挥作用至关重要。 此更改引入了服务并授予必要的权限。

如需包含在应用程序中的此方法的完整示例,请参阅 .NET MAUI Community 工具包示例应用程序

支持的格式

每个平台支持的多媒体格式可能有所不同。 在某些情况下,它甚至可能取决于运行应用时所用操作系统上提供或安装了哪些解码器。 有关每个平台上支持哪些格式的更多详细信息,请参阅以下链接。

平台 链接 说明
Android ExoPlayer 支持的格式
iOS/macOS iOS/macOS 支持的格式 有关此内容的官方文档不存在
Windows Windows 支持的格式 在 Windows 上,支持的格式在很大程度上取决于用户计算机上安装的编解码器
Tizen Tizen 支持的格式

重要

如果用户使用的是 Windows N 版本,则默认情况下不支持视频播放。 Windows N 版本有意未安装视频播放格式。

常见方案

以下各节介绍了 MediaElement 的常见使用方案。

播放远程媒体

MediaElement 可以使用 HTTP 和 HTTPS URI 方案播放远程媒体文件。 这可通过将 Source 属性设置为媒体文件的 URI 来实现:

<toolkit:MediaElement Source="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
              ShouldShowPlaybackControls="True" />

重要

从 HTTP 终结点播放远程源时,可能需要禁用阻止访问不安全 Web 终结点的操作系统安全措施。 这至少适用于 iOS 和 Android。

默认情况下,Source 属性定义的媒体不会在媒体打开后立即开始播放。 要启用自动媒体播放,请将 ShouldAutoPlay 属性设置为 true

平台提供的媒体播放控件默认处于启用状态,可以通过将 ShouldShowPlaybackControls 属性设置为 false 将其禁用。

使用元数据

MediaElement 可以将元数据用于 MediaElement.MetadataTitleMediaElement.MetadataArtistMediaElement.MetadataArtworkUrl。 你可以在 Windows、Mac Catalyst、iOS 和 Android 的锁屏控件上设置标题或艺术家,以显示当前播放的内容。 可以使用锁屏的插图设置本地或远程 URL。 至少应为 1080P 才能显示最佳质量。 它必须是 URL,并且为 .jpg.png

<toolkit:MediaElement 
    MetadataTitle="Title"
    MetadataArtist="Artist"
    MetadataArtworkUrl="http://www.myownpersonaldomain.com/image.jpg" />
    MediaElement.MetadataTitle="Title";
    MediaElement.MetadataArtist="Artist";
    MediaElement.MetadataArtworkUrl="http://www.myownpersonaldomain.com/image.jpg";

重要

可以在 XAML 或代码隐藏中设置元数据。 如果要在代码隐藏中设置它,则需要在代码隐藏中设置源代码。 应最后设置源。 如果在 XAML 或构造函数中设置元数据,则可以安全地忽略此注释。

播放本地媒体

可以从以下源播放本地媒体:

  • 使用 embed:// URI 方案嵌入平台应用程序中的资源。
  • 使用 filesystem:// URI 方案的来自应用的本地文件系统的文件。

注意

简写 embed://filesystem:// 只能在 XAML 中使用。 在代码中,请分别使用 MediaSource.FromResource()MediaSource.FromFile()。 使用这些方法,可以省略 embed://filesystem:// 前缀。 路径的其余部分应相同。

播放嵌入在应用包中的媒体

MediaElement 可以使用 embed:// URI 方案播放嵌入应用包中的媒体文件。 媒体文件通过将它们放在平台项目中来嵌入到应用包中。

要启用媒体文件以便从本地资源播放,请将该文件添加到 .NET MAUI 项目的 Resources/Raw 文件夹。 在根目录中添加文件时,URI 将为 embed://MyFile.mp4

还可以将文件放在子文件夹中。 如果 MyFile.mp4 位于 Resources/Raw/MyVideos 中,则要与 MediaElement 一起使用它的 URI 将是 embed://MyVideos/MyFile.mp4

如何在 XAML 中使用此语法的示例如下所示。

<toolkit:MediaElement Source="embed://MyFile.mp4"
              ShouldShowPlaybackControls="True" />

了解 MediaSource 类型

MediaElement 可以通过将其 Source 属性设置为远程或本地媒体文件来播放媒体。 Source 属性的类型为 MediaSource,此类定义三种静态方法:

  • FromFile,从 string 参数返回 FileMediaSource 实例。
  • FromUri,从 Uri 参数返回 UriMediaSource 实例。
  • FromResource,从 string 参数返回 ResourceMediaSource 实例。

此外,MediaSource 类还包含从 stringUri 参数返回 MediaSource 实例的隐式运算符。

注意

在 XAML 中设置 Source 属性时,将调用类型转换器从 stringUri 返回 MediaSource 实例。

MediaSource 类还包含以下派生类:

  • FileMediaSource,用于指定 string 中的本地媒体文件。 此类包含可设置为 stringPath 属性。 此外,此类还包含将 string 转换为 FileMediaSource 对象,并将 FileMediaSource 对象转换为 string 的隐式运算符。
  • UriMediaSource,用于指定 URI 中的远程媒体文件。 此类包含可设置为 UriUri 属性。
  • ResourceMediaSource,用于指定通过应用的资源文件提供的嵌入文件。 此类包含可设置为 stringPath 属性。

注意

在 XAML 中创建 FileMediaSource 对象时,将调用类型转换器从 string 返回 FileMediaSource 实例。

更改视频纵横比

Aspect 属性确定如何缩放视频媒体以适应显示区域。 默认情况下,此属性设置为 AspectFit 枚举成员,但可以设置为任何 Aspect 枚举成员:

  • AspectFit 指示视频将采用黑边(如果需要)以适应显示区域,同时保留纵横比。
  • AspectFill 指示视频将被剪裁,以便它填充显示区域,同时保留纵横比。
  • Fill 指示视频将被拉伸以填充显示区域。

确定 MediaElement 状态

MediaElement 类定义名为 CurrentState 的只读可绑定属性,类型为 MediaElementState。 此属性指示控件的当前状态,例如媒体是在播放还是暂停,或者是否尚未准备好播放媒体。

MediaElementState 枚举定义以下成员:

  • None 指示 MediaElement 不包含媒体。
  • Opening 指示 MediaElement 正在验证并尝试加载指定的源。
  • Buffering 指示 MediaElement 正在加载要播放的媒体。 其 Position 属性在此状态下不会推进。 如果 MediaElement 播放过视频,它将继续显示最后显示的帧。
  • Playing 指示 MediaElement 正在播放媒体源。
  • Paused 指示 MediaElement 不推进其 Position 属性。 如果 MediaElement 播放过视频,它将继续显示当前帧。
  • Stopped 指示 MediaElement 包含媒体但未播放或暂停。 其 Position 属性重置为 0,并且不会推进。
  • Failed 指示 MediaElement 无法加载或播放媒体。 尝试加载新媒体项、尝试播放媒体项或媒体播放因故障中断时,可能会发生这种情况。 使用 MediaFailed 事件检索其他详细信息。

使用 MediaElement 传输控件时,通常不需要检查 CurrentState 属性。 但是,在实现自己的传输控件时,此属性变得非常重要。

实现自定义传输控件

媒体播放器的传输控件包括执行“播放”、“暂停”和“停止”功能的按钮。 这些按钮通常使用熟悉的图标而非文本来标识,且“播放”和“暂停”功能通常合并成一个按钮

默认情况下,MediaElement 播放控件处于禁用状态。 这样一来,可以以编程方式或通过提供自己的传输控件控制 MediaElement。 为了支持此功能,MediaElement 包括 PlayPauseStop 方法。

以下 XAML 示例显示包含 MediaElement 和自定义传输控件的页面:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             x:Class="MediaElementDemos.CustomTransportPage"
             Title="Custom transport">
    <Grid>
        ...
        <toolkit:MediaElement x:Name="mediaElement"
                      ShouldAutoPlay="False"
                      ... />
        <HorizontalStackLayout BindingContext="{x:Reference mediaElement}"
                     ...>
            <Button Text="Play"
                    HorizontalOptions="Center"
                    Clicked="OnPlayPauseButtonClicked">
                <Button.Triggers>
                    <DataTrigger TargetType="Button"
                                 Binding="{Binding CurrentState}"
                                 Value="{x:Static toolkit:MediaElementState.Playing}">
                        <Setter Property="Text"
                                Value="Pause" />
                    </DataTrigger>
                    <DataTrigger TargetType="Button"
                                 Binding="{Binding CurrentState}"
                                 Value="{x:Static toolkit:MediaElementState.Buffering}">
                        <Setter Property="IsEnabled"
                                Value="False" />
                    </DataTrigger>
                </Button.Triggers>
            </Button>
            <Button Text="Stop"
                    HorizontalOptions="Center"
                    Clicked="OnStopButtonClicked">
                <Button.Triggers>
                    <DataTrigger TargetType="Button"
                                 Binding="{Binding CurrentState}"
                                 Value="{x:Static toolkit:MediaElementState.Stopped}">
                        <Setter Property="IsEnabled"
                                Value="False" />
                    </DataTrigger>
                </Button.Triggers>
            </Button>
        </HorizontalStackLayout>
    </Grid>
</ContentPage>

在此示例中,自定义传输控件定义为 Button 对象。 但是,只有两个 Button 对象,第一个 Button 表示“播放”和“暂停”,第二个 Button 表示“停止”DataTrigger 对象用于启用和禁用按钮,以及在“播放”和“暂停”之间切换第一个按钮。 有关数据触发器的详细信息,请参阅 .NET MAUI 触发器

代码隐藏文件包含 Clicked 事件的处理程序:

void OnPlayPauseButtonClicked(object sender, EventArgs args)
{
    if (mediaElement.CurrentState == MediaElementState.Stopped ||
        mediaElement.CurrentState == MediaElementState.Paused)
    {
        mediaElement.Play();
    }
    else if (mediaElement.CurrentState == MediaElementState.Playing)
    {
        mediaElement.Pause();
    }
}

void OnStopButtonClicked(object sender, EventArgs args)
{
    mediaElement.Stop();
}

“播放”按钮启用后,即可按下它开始播放。 按“暂停”按钮会导致播放暂停。 按“停止”按钮停止播放,并将媒体文件的位置返回到开头。

实现自定义音量控件

每个平台实现的媒体播放控件都包括音量条。 此音量条类似于滑块,并显示媒体的音量。 此外,还可以操作音量条来调高或调低音量。

可以使用 Slider 实现自定义音量条,如以下示例所示:

<StackLayout>
    <toolkit:MediaElement ShouldAutoPlay="False"
                          Source="{StaticResource AdvancedAsync}" />
    <Slider Maximum="1.0"
            Minimum="0.0"
            Value="{Binding Volume}"
            Rotation="270"
            WidthRequest="100" />
</StackLayout>

在此示例中,Slider 数据将其 Value 属性绑定到 MediaElementVolume 属性。 这是可能的,因为 Volume 属性使用 TwoWay 绑定。 因此,更改 Value 属性将导致 Volume 属性更改。

注意

Volume 属性包含验证回调,可确保其值大于或等于 0.0,并且小于或等于 1.0。

有关使用 Slider 的详细信息,请参阅 .NET MAUI 滑块

清理 MediaElement 资源

要防止内存泄漏,必须释放 MediaElement 的资源。 可以通过断开处理程序的连接来完成此操作。 需要执行此操作的位置取决于应用中使用 MediaElement 的位置和方式,但通常如果在单个页面上包含 MediaElement 并且未在后台播放媒体,则需要在用户离开页面时释放资源。

下面可以找到演示如何执行此操作的示例代码片段。 首先,请确保在页面上挂接 Unloaded 事件。

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             x:Class="MediaElementDemos.FreeResourcesPage"
             Title="Free Resources"
             Unloaded="ContentPage_Unloaded">
    
    <toolkit:MediaElement x:Name="mediaElement"
                          ShouldAutoPlay="False"
                          ... />
</ContentPage>

然后在代码隐藏中,调用该方法以断开处理程序的连接。

public partial class FreeResourcesPage : ContentPage
{
    void ContentPage_Unloaded(object? sender, EventArgs e)
    {
        // Stop and cleanup MediaElement when we navigate away
        mediaElement.Handler?.DisconnectHandler();
    }
}

要详细了解处理程序,请参阅有关处理程序的 .NET MAUI 文档。

属性

属性 类型​​ 说明 默认值
方面 方面 确定当前加载的(视觉对象)媒体的缩放模式。 这是一种可绑定属性。 Aspect.AspectFit
CurrentState MediaElementState 指示控件的当前状态。 这是一种只读可绑定属性。 MediaElementState.None
持续时间 TimeSpan 指示当前打开的媒体的持续时间。 这是一种只读可绑定属性。 TimeSpan.Zero
位置 TimeSpan 介绍媒体播放时间的当前进度。 这是一种只读可绑定属性。 如果要设置 Position,请使用 SeekTo() 方法。 TimeSpan.Zero
ShouldAutoPlay bool 指示设置 Source 属性时是否自动开始播放媒体。 这是一种可绑定属性。 false
ShouldLoopPlayback bool 介绍当前加载的媒体源在播放结束后是否应从头恢复播放。 这是一种可绑定属性。 false
ShouldKeepScreenOn bool 确定设备屏幕是否应在媒体播放期间保持打开状态。 这是一种可绑定属性。 false
ShouldMute bool 确定音频当前是否静音。 这是一种可绑定属性。 false
ShouldShowPlaybackControls bool 确定是否显示平台播放控件。 这是一种可绑定属性。 请注意,在 iOS 和 Windows 上,这些控件仅在与屏幕交互后显示一小段时间。 无法始终使这些控件保持可见。 true
Source MediaSource? 加载到控件中的媒体的源。 null
速度 double 确定媒体的播放速度。 这是一种可绑定属性 1
MediaHeight int 加载媒体的高度(以像素为单位)。 这是一种只读可绑定属性。 非可视媒体未报告,可能不会始终在 iOS/macOS 上填充实时流式传输内容。 0
MediaWidth int 加载媒体的宽度(以像素为单位)。 这是一种只读可绑定属性。 非可视媒体未报告,可能不会始终在 iOS/macOS 上填充实时流式传输内容。 0
体积 double 确定媒体的音量,以 0 到 1 之间的线性标尺表示。 这是一种可绑定属性。 1

事件

事件 说明
MediaOpened 在验证并打开媒体流时发生。
MediaEnded MediaElement 播放完其媒体时发生。
MediaFailed 当存在与媒体源关联的错误时发生。
PositionChanged Position 属性值更改后发生。
SeekCompleted 当请求的查找操作的查找点准备好播放时发生。

方法

事件 说明
玩游戏 开始播放加载的媒体。
暂停 暂停播放当前媒体。
停止 停止播放并重置当前媒体的位置。
SeekTo 取一个 TimeSpan 值来设置 Position 属性,取一个 CancellationToken 来取消 Task

示例

可以在 .NET MAUI 社区工具包示例应用程序中查找此控件操作的示例。

API

可以在 .NET MAUI 社区工具包 GitHub 存储库上查找 MediaElement 的源代码。