Xamarin Community Toolkit MediaElement

下載範例。 下載範例

MediaElement 是播放視訊和音訊的檢視。 基礎平臺支援的媒體可從下列來源播放:

  • Web,使用 URI (HTTP 或 HTTPS) 。
  • 使用 ms-appx:/// URI 配置內嵌在平臺應用程式中的資源。
  • 使用 URI 配置,來自應用程式的本機和暫存資料檔案夾的 ms-appdata:/// 檔案。
  • 裝置的程式庫。

MediaElement 可以使用平臺播放控制項,這稱為傳輸控制項。 不過,預設會停用它們,並可取代為您自己的傳輸控制項。 下列螢幕擷取畫面顯示 MediaElement 使用平臺傳輸控制項播放影片:

在 iOS 和 Android 上播放影片的 MediaElement 螢幕擷取畫面。

注意

MediaElement適用于 iOS、Android、通用 Windows 平臺 (UWP) 、macOS、Windows Presentation Foundation和 Tizen。

MediaElement 會定義下列屬性:

  • Aspect類型 Aspect 為 的 ,決定媒體如何調整以符合顯示區域。 此屬性的預設值為 AspectFit
  • AutoPlay類型 bool 為 的 ,指出設定 屬性時 Source ,媒體播放是否會自動開始。 此屬性的預設值為 true
  • BufferingProgress類型 double 為 的 ,表示目前的緩衝進度。 此屬性的預設值為 0.0。
  • CanSeek類型 bool 為 的 ,指出媒體是否可以藉由設定 屬性的值 Position 來重新置放。 這是一個唯讀屬性。
  • CurrentState類型 MediaElementState 為 的 ,表示控制項的目前狀態。 這是唯讀屬性,其預設值為 MediaElementState.Closed
  • Duration類型 TimeSpan? 為 的 ,表示目前開啟媒體的持續時間。 這是唯讀屬性,其預設值為 null
  • IsLooping類型 bool 為 的 ,描述目前載入的媒體來源是否應該在到達其結束之後從開始繼續播放。 此屬性的預設值為 false
  • KeepScreenOn類型 bool 為 的 ,可判斷裝置畫面是否應該在媒體播放期間保持開啟。 此屬性的預設值為 false
  • Position類型 TimeSpan 為 的 ,描述媒體播放時間的目前進度。 此屬性使用系 TwoWay 結,其預設值為 TimeSpan.Zero
  • ShowsPlaybackControls類型 bool 為 的 ,決定是否顯示平臺播放控制項。 此屬性的預設值為 false。 請注意,在 iOS 上,控制項只會在與畫面互動之後顯示一段短暫的時間。 無法隨時讓控制項保持可見。 在 WPF 上,不支援系統控制項,因此此屬性沒有任何作用。
  • Speed類型 double 為 的 ,決定媒體的播放速度。 這個屬性的預設值為 1。
  • Source類型 MediaSource 為 的 ,表示載入控制項的媒體來源。
  • VideoHeight類型 int 為 的 ,表示控制項的高度。 這是一個唯讀屬性。
  • VideoWidth類型 int 為 的 ,表示控制項的寬度。 這是一個唯讀屬性。
  • Volume類型 double 為 的 ,會決定媒體的磁片區,以介於 0 到 1 之間的線性刻度表示。 此屬性使用系 TwoWay 結,其預設值為 1。

除了 屬性之外 CanSeek ,這些屬性是由 物件所支援 BindableProperty ,這表示這些屬性可以是資料系結的目標,並設定樣式。

類別 MediaElement 也會定義四個事件:

  • MediaOpened 在媒體資料流程經過驗證並開啟時引發。
  • MediaEnded 會在 完成播放其媒體時 MediaElement 引發。
  • MediaFailed 當媒體來源發生相關錯誤時,就會引發 。
  • SeekCompleted 當所要求搜尋作業的搜尋點準備好播放時,就會引發 。

此外, MediaElement 還包含 PlayPauseStop 方法。

如需 Android 上支援媒體格式的資訊,請參閱支援 developer.android.com 的 媒體格式 。 如需通用 Windows 平臺 (UWP) 上支援媒體格式的資訊,請參閱支援的編解碼器

播放遠端媒體

MediaElement可以使用 HTTP 和 HTTPS URI 配置播放遠端媒體檔案。 這可藉由將 Source 屬性設定為媒體檔案的 URI 來完成:

<MediaElement Source="https://sec.ch9.ms/ch9/5d93/a1eab4bf-3288-4faf-81c4-294402a85d93/XamarinShow_mid.mp4"
              ShowsPlaybackControls="True" />

根據預設,屬性所 Source 定義的媒體會在媒體開啟之後立即播放。 若要隱藏自動媒體播放,請將 AutoPlay 屬性設定為 false

預設會停用媒體播放控制項,並將 屬性設定 ShowsPlaybackControlstrue 來啟用。 MediaElement 接著會使用可用的平臺播放控制項。

播放本機媒體

您可以從下列來源播放本機媒體:

  • 使用 ms-appx:/// URI 配置內嵌在平臺應用程式中的資源。
  • 使用 URI 配置,來自應用程式的本機和暫存資料檔案夾的 ms-appdata:/// 檔案。
  • 裝置的程式庫。

如需這些 URI 配置的詳細資訊,請參閱 URI 配置

播放內嵌在應用程式套件中的媒體

MediaElement可以使用 URI 配置播放內嵌在應用程式套件 ms-appx:/// 中的媒體檔案。 媒體檔案會內嵌在應用程式套件中,方法是將它們放在平臺專案中。

在每個平臺專案中儲存媒體檔案會有所不同:

  • 在 iOS 上,媒體檔案必須儲存在 Resources 資料夾或 Resources 資料夾的子資料夾中。 媒體檔案必須具有 Build ActionBundleResource
  • 在 Android 上,媒體檔案必須儲存 在名為raw的資源子資料夾中。 raw 資料夾不能包含子資料夾。 媒體檔案必須具有 Build ActionAndroidResource
  • 在 UWP 上,媒體檔案可以儲存在專案中的任何資料夾中。 媒體檔案必須具有 BuildActionContent

然後,您可以使用 URI 配置來播放符合這些準則的 ms-appx:/// 媒體檔案:

<MediaElement Source="ms-appx:///XamarinForms101UsingEmbeddedImages.mp4"
              ShowsPlaybackControls="True" />

使用資料系結時,可以使用值轉換器來套用此 URI 配置:

public class VideoSourceConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null)
            return null;

        if (string.IsNullOrWhiteSpace(value.ToString()))
            return null;

        if (Device.RuntimePlatform == Device.UWP)
            return new Uri($"ms-appx:///Assets/{value}");
        else
            return new Uri($"ms-appx:///{value}");
    }
    // ...
}

接著,可以使用 的 VideoSourceConverter 實例,將 URI 配置套 ms-appx:/// 用至內嵌媒體檔案:

<MediaElement Source="{Binding MediaSource, Converter={StaticResource VideoSourceConverter}}"
              ShowsPlaybackControls="True" />

如需 ms-appx URI 配置的詳細資訊,請參閱 ms-appx 和 ms-appx-web

從應用程式的本機和暫存資料夾播放媒體

MediaElement可以使用 URI 配置,播放複製到應用程式本機或暫存資料檔案夾 ms-appdata:/// 的媒體檔案。

下列範例顯示 Source 屬性設定為儲存在應用程式本機資料檔案夾中的媒體檔案:

<MediaElement Source="ms-appdata:///local/XamarinVideo.mp4"
              ShowsPlaybackControls="True" />

下列範例顯示儲存 Source 在應用程式暫存資料檔案夾中之媒體檔案的屬性:

<MediaElement Source="ms-appdata:///temp/XamarinVideo.mp4"
              ShowsPlaybackControls="True" />

重要

除了播放儲存在應用程式本機或暫存資料檔案夾中的媒體檔案之外,UWP 也可以播放位於應用程式漫遊資料夾中的媒體檔案。 藉由將媒體檔案 ms-appdata:///roaming/ 前置詞加上 ,即可達成此目的。

使用資料系結時,可以使用值轉換器來套用此 URI 配置:

public class VideoSourceConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null)
            return null;

        if (string.IsNullOrWhiteSpace(value.ToString()))
            return null;

        return new Uri($"ms-appdata:///{value}");
    }
    // ...
}

接著,可以使用 的 VideoSourceConverter 實例,將 URI 配置套 ms-appdata:/// 用至應用程式本機或暫存資料檔案夾中的媒體檔案:

<MediaElement Source="{Binding MediaSource, Converter={StaticResource VideoSourceConverter}}"
              ShowsPlaybackControls="True" />

如需 ms-appdata URI 配置的詳細資訊,請參閱 ms-appdata

將媒體檔案複製到應用程式的本機或暫存資料檔案夾

播放儲存在應用程式本機或暫存資料檔案夾中的媒體檔案,需要應用程式將媒體檔案複製到該處。 例如,藉由從應用程式套件複製媒體檔案,即可完成此作業:

// This method copies the video from the app package to the app data
// directory for your app. To copy the video to the temp directory
// for your app, comment out the first line of code, and uncomment
// the second line of code.
public static async Task CopyVideoIfNotExists(string filename)
{
    string folder = FileSystem.AppDataDirectory;
    //string folder = Path.GetTempPath();
    string videoFile = Path.Combine(folder, "XamarinVideo.mp4");

    if (!File.Exists(videoFile))
    {
        using (Stream inputStream = await FileSystem.OpenAppPackageFileAsync(filename))
        {
            using (FileStream outputStream = File.Create(videoFile))
            {
                await inputStream.CopyToAsync(outputStream);
            }
        }
    }
}

注意

上述程式碼範例會 FileSystem 使用 Xamarin.Essentials 中包含的 類別。 如需詳細資訊,請參閱 Xamarin.Essentials:檔案系統協助程式

從裝置媒體櫃播放媒體

大部分的新式行動裝置和桌上型電腦都能夠使用裝置的相機和麥克風來錄製視訊和音訊。 接著,建立的媒體會儲存為裝置上的檔案。 您可以從程式庫擷取這些檔案,並由 播放 MediaElement

每個平臺都包含一個功能,可讓使用者從裝置的程式庫選取媒體。 在 Xamarin.Forms 中,平臺專案可以叫用這項功能,而且可由 類別呼叫 DependencyService

範例應用程式中所使用的影片挑選相依性服務與 從圖片庫挑選相片中所定義的相依性服務非常類似,不同之處在于選擇器會傳回檔案名,而不是 Stream 物件。 共用程式碼專案會定義名為 的 IVideoPicker 介面,該介面會定義名為 GetVideoFileAsync 的單一方法。 然後,每個平臺都會在 類別中實作 VideoPicker 這個介面。

下列程式碼範例示範如何從裝置程式庫擷取媒體檔案:

string filename = await DependencyService.Get<IVideoPicker>().GetVideoFileAsync();
if (!string.IsNullOrWhiteSpace(filename))
{
    mediaElement.Source = new FileMediaSource
    {
        File = filename
    };
}

呼叫 方法來取得平臺專案中介面的實作 IVideoPicker ,以叫 DependencyService.Get 用影片挑選相依性服務。 GetVideoFileAsync然後,在該實例上呼叫 方法,並使用傳回的檔案名來建立 FileMediaSource 物件,並將它設定為 SourceMediaElement 屬性。

變更視訊外觀比例

屬性 Aspect 會決定視訊媒體的縮放方式,以符合顯示區域。 根據預設,此屬性會設定為 AspectFit 列舉成員,但可以設定為任何 Aspect 列舉成員:

  • AspectFit 表示視訊會視需要收件匣,以符合顯示區域,同時保留外觀比例。
  • AspectFill 表示會裁剪視訊,使其填滿顯示區域,同時保留外觀比例。
  • Fill 表示視訊會延展以填滿顯示區域。

系結至 Position 屬性

播放時,可系結屬性的屬性變更通知 Position 會以 200 毫秒間隔引發。 因此,屬性可以系結至 Slider 控制項 (或類似) ,以透過媒體顯示進度。 CommunityToolkit 也提供 , TimeSpanToDoubleConverter 其會將 TimeSpan 轉換成浮點值,代表經過的總秒數。 如此一來,您可以將 Slider Maximum 設定為 Duration 媒體的 , Value 並將 設定為 , Position 以提供精確的進度:

<?xml version="1.0" encoding="UTF-8"?>
<pages:BasePage xmlns="http://xamarin.com/schemas/2014/forms"
                xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
                xmlns:pages="clr-namespace:Xamarin.CommunityToolkit.Sample.Pages"
                x:Class="Xamarin.CommunityToolkit.Sample.Pages.Views.MediaElementPage">
    <pages:BasePage.Resources>
        <xct:TimeSpanToDoubleConverter x:Key="TimeSpanConverter"/>
    </pages:BasePage.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <xct:MediaElement
            x:Name="mediaElement"
            Source="https://sec.ch9.ms/ch9/5d93/a1eab4bf-3288-4faf-81c4-294402a85d93/XamarinShow_mid.mp4"
            ShowsPlaybackControls="True"
            HorizontalOptions="Fill"
            SeekCompleted="OnSeekCompleted" />
        <Slider Grid.Row="1" BindingContext="{x:Reference mediaElement}" Value="{Binding Position, Converter={StaticResource TimeSpanConverter}}" Maximum="{Binding Duration, Converter={StaticResource TimeSpanConverter}}">
            <Slider.Triggers>
                <DataTrigger TargetType="Slider"
                     Binding="{Binding CurrentState}"
                     Value="{x:Static MediaElementState.Buffering}">
                    <Setter Property="IsEnabled" Value="False" />
                </DataTrigger>
            </Slider.Triggers>
        </Slider>
        <Button Grid.Row="2" Text="Reset Source (Set Null)" Clicked="OnResetClicked" />
    </Grid>
</pages:BasePage>

在此範例中 Maximum ,的 Slider 屬性會系結至 DurationMediaElement 屬性,而 ValueSlider 屬性則系結至 Position 的 屬性 MediaElement 。 因此,拖 Slider 曳媒體播放位置的結果會變更:

iOS 和 Android 上具有位置列的 MediaElement 螢幕擷取畫面。

此外,當媒體進行緩衝處理時, DataTrigger 會使用 物件來停用 Slider 。 如需資料觸發程式的詳細資訊,請參閱 Xamarin.Forms 觸發程式

注意

在 Android 上, Slider 不論 和 Maximum 設定為何, Minimum 只有 1000 個離散步驟。 如果媒體長度大於 1000 秒,則兩個不同的 Position 值會對應至 相同的 ValueSlider 。 這就是為什麼上述程式碼會檢查新位置和現有位置是否大於整體持續時間的一百分之一。

瞭解 MediaSource 類型

MediaElement可以播放媒體,方法是將其 Source 屬性設定為遠端或本機媒體檔案。 屬性 Source 的類型為 MediaSource ,而這個類別會定義兩個靜態方法:

  • FromFile會從 string 引數傳回 MediaSource 實例。
  • FromUri會從 Uri 引數傳回 MediaSource 實例。

此外,類別 MediaSource 也有從 和 Uri 引數傳回 MediaSource 實例 string 的隱含運算子。

注意

Source在 XAML 中設定 屬性時,會叫用型別轉換器,以從 string 或 傳 UriMediaSource 實例。

類別 MediaSource 也有兩個衍生類別:

  • UriMediaSource,用來從 URI 指定遠端媒體檔案。 這個類別具有 Uri 可設定為 Uri 的屬性。
  • FileMediaSource,用來指定 的 string 本機媒體檔案。 這個類別具有 File 可設定為 string 的屬性。 此外,這個類別具有隱含運算子,可將 轉換成 物件,並將 FileMediaSource 物件轉換成 stringstringFileMediaSource

注意

FileMediaSource在 XAML 中建立 物件時,會叫用型別轉換器,以從 string 傳回 FileMediaSource 實例。

判斷 MediaElement 狀態

類別 MediaElement 會定義名為 的唯讀可系結屬性,其 CurrentState 類型為 MediaElementState 。 這個屬性工作表示控制項的目前狀態,例如媒體現正播放或暫停,或者它尚未準備好播放媒體。

MediaElementState 列舉會定義下列成員:

  • Closed 表示 MediaElement 不包含媒體。
  • Opening 表示 正在 MediaElement 驗證並嘗試載入指定的來源。
  • Buffering 表示 MediaElement 正在載入媒體以供播放。 其 Position 屬性不會在此狀態期間前進。 MediaElement如果 現正播放視訊,它會繼續顯示最後一個顯示的框架。
  • Playing 表示 MediaElement 現正播放媒體來源。
  • Paused 表示 MediaElement 不會前進其 Position 屬性。 MediaElement如果 現正播放視訊,它會繼續顯示目前的畫面。
  • Stopped 表示 MediaElement 包含媒體,但未播放或暫停。 其 Position 屬性為 0,且不會前進。 如果載入的媒體是視訊,則會 MediaElement 顯示第一個畫面。

使用 MediaElement 傳輸控制項時,通常不需要檢查 CurrentState 屬性。 不過,實作您自己的傳輸控制項時,這個屬性會變得很重要。

實作自訂傳輸控制項

媒體播放程式的傳輸控制項包含執行 播放暫停停止函式的按鈕。 這些按鈕通常會以熟悉的圖示而非文字呈現,且 [播放] 及 [暫停] 功能常會合併為一個按鈕。

根據預設, MediaElement 會停用播放控制項。 這可讓您 MediaElement 以程式設計方式或提供自己的傳輸控制項來控制 。 支援此功能時, MediaElement 包括 PlayPauseStop 方法。

下列 XAML 範例顯示包含 MediaElement 和 自訂傳輸控制項的頁面:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MediaElementDemos.CustomTransportPage"
             Title="Custom transport">
    <Grid>
        ...
        <MediaElement x:Name="mediaElement"
                      AutoPlay="False"
                      ... />
        <StackLayout BindingContext="{x:Reference mediaElement}"
                     ...>
            <Button Text="&#x25B6;&#xFE0F; Play"
                    HorizontalOptions="CenterAndExpand"
                    Clicked="OnPlayPauseButtonClicked">
                <Button.Triggers>
                    <DataTrigger TargetType="Button"
                                 Binding="{Binding CurrentState}"
                                 Value="{x:Static MediaElementState.Playing}">
                        <Setter Property="Text"
                                Value="&#x23F8; Pause" />
                    </DataTrigger>
                    <DataTrigger TargetType="Button"
                                 Binding="{Binding CurrentState}"
                                 Value="{x:Static MediaElementState.Buffering}">
                        <Setter Property="IsEnabled"
                                Value="False" />
                    </DataTrigger>
                </Button.Triggers>
            </Button>
            <Button Text="&#x23F9; Stop"
                    HorizontalOptions="CenterAndExpand"
                    Clicked="OnStopButtonClicked">
                <Button.Triggers>
                    <DataTrigger TargetType="Button"
                                 Binding="{Binding CurrentState}"
                                 Value="{x:Static MediaElementState.Stopped}">
                        <Setter Property="IsEnabled"
                                Value="False" />
                    </DataTrigger>
                </Button.Triggers>
            </Button>
        </StackLayout>
    </Grid>
</ContentPage>

在此範例中,自訂傳輸控制項會定義為 Button 物件。 不過,只有兩 Button 個物件,第一個 Button 代表 PlayPause,第二個 Button 代表 StopDataTrigger 物件可用來啟用和停用按鈕,以及切換 播放暫停之間的第一個按鈕。 如需資料觸發程式的詳細資訊,請參閱 Xamarin.Forms 觸發程式

程式碼後置檔案具有事件的處理常式 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();
}

一旦啟用 [播放] 按鈕,就可以按下 [ 播放 ] 按鈕,開始播放:

iOS 和 Android 上具有自訂傳輸控制項的 MediaElement 螢幕擷取畫面。

按下 [暫停] 按鈕會導致播放暫停:

在 iOS 和 Android 上暫停播放的 MediaElement 螢幕擷取畫面。

按下 [停止] 按鈕會停止播放,並將媒體檔案的位置傳回至開頭。

實作自訂磁片區控制項

每個平臺所實作的媒體播放控制項都包含音量列。 此列類似于滑杆,並顯示媒體的音量。 此外,您可以操作磁片區列來增加或減少磁片區。

您可以使用 來實 Slider 作自訂磁片區列,如下列範例所示:

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

在此範例中 Slider ,資料會將其 Value 屬性系結至 VolumeMediaElement 屬性。 這是可行的, Volume 因為 屬性使用系 TwoWay 結。 因此,變更 Value 屬性會導致 Volume 屬性變更。

注意

Volume屬性具有驗證回呼,可確保其值大於或等於 0.0,且小於或等於 1.0。

如需使用 Slider 的詳細資訊,請參閱 Xamarin.Forms 滑杆