MediaElement – это представление для воспроизведения видео и аудио. Медиафайлы, поддерживаемые базовой платформой, могут воспроизводиться из следующих источников:
- Веб-ресурс, используя URI (HTTP или HTTPS).
- Ресурс, встроенный в приложение платформы, с использованием схемы URI ms-appx:///.
- Файлы из локальных и временных папок данных приложения, использующие схему URI ms-appdata:///.
- Библиотека устройства.
MediaElement может использовать элементы управления воспроизведением платформы, которые называются транспортными элементами управления. Однако по умолчанию они отключены и могут быть заменены собственными транспортными элементами управления. На следующих скриншотах показано воспроизведение видео в MediaElement с использованием транспортных элементов платформы:
Примечание. MediaElement доступен на iOS, Android, Universal Windows Platform (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, описывает текущий прогресс по времени воспроизведения медиафайла. Это свойство использует двухстороннюю привязку, а его значение по умолчанию – 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 – когда медиаэлемент завершает воспроизведение своего медиапотока.
- MediaFailed происходит, когда возникает ошибка, связанная с источником мультимедиа.
- SeekCompleted выполняется, когда точка поиска в запрошенной операции поиска готова к воспроизведению.
Кроме того, MediaElement содержит методы Play, Pause и Stop.
Воспроизведение удаленных медиафайлов
Элемент MediaElement может воспроизводить удаленные медиафайлы, используя схемы URI HTTP и HTTPS. Для этого нужно установить свойство Source в URI медиафайла:
<MediaElement Source="https://sec.ch9.ms/ch9/5d93/a1eab4bf-3288-4faf-81c4-294402a85d93/XamarinShow_mid.mp4"
ShowsPlaybackControls="True" />
По умолчанию носитель, заданный свойством Source, воспроизводится сразу после его открытия. Чтобы отключить автоматическое воспроизведение мультимедиа, установите для свойства AutoPlay значение false.
Элементы управления воспроизведением медиафайлов по умолчанию отключены, их можно включить, установив свойство ShowsPlaybackControls в true. В этом случае MediaElement будет использовать элементы управления воспроизведением платформы, если они доступны.
Воспроизведение локальных медиафайлов
Локальные медиафайлы могут быть воспроизведены из следующих источников:
- Ресурс, встроенный в приложение платформы, с использованием схемы URI ms-appx:///.
- Файлы из локальных и временных папок данных приложения, использующие схему URI ms-appdata:///.
- Библиотека устройства.
Воспроизведение медиафайлов, встроенных в пакет приложения
Элемент MediaElement может воспроизводить медиафайлы, встроенные в пакет приложения, используя схему URI ms-appx:///. Медиафайлы встраиваются в пакет приложения путем их размещения в проекте платформы.
Хранение медиафайла в проекте платформы для каждой платформы различно:
- На iOS медиафайлы должны храниться в папке Resources или в подпапке папки Resources. Медиафайл должен иметь Build Action BundleResource.
- На Android медиафайлы должны храниться во вложенной папке Resources с именем raw. Папка raw не может содержать вложенных папок. Медиафайл должен иметь действие сборки AndroidResource.
- В UWP медиафайлы могут храниться в любой папке проекта. Медиафайл должен иметь BuildAction of Content.
Медиафайлы, удовлетворяющие этим критериям, могут быть воспроизведены с помощью схемы 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" />
Воспроизведение медиафайлов из локальных и временных папок приложения
Элемент 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" />
Копирование медиафайла в локальную или временную папку данных приложения
Для воспроизведения медиафайла, хранящегося в локальной или временной папке данных приложения, необходимо, чтобы приложение скопировало его туда. Это можно сделать, например, скопировав медиафайл из пакета приложения:
// 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().GetVideoFileAsync(); if (!string.IsNullOrWhiteSpace(filename)) { mediaElement.Source = new FileMediaSource { File = filename }; }
Сервис зависимостей для подбора видеофайлов вызывается методом DependencyService.Get для получения реализации интерфейса IVideoPicker в проекте платформы. Затем для этого экземпляра вызывается метод GetVideoFileAsync, а возвращаемое имя файла используется для создания объекта FileMediaSource и установки его в свойство Source элемента MediaElement.
Изменение соотношения сторон видео
Свойство Aspect определяет, как будет масштабироваться видеоданные для соответствия области отображения. По умолчанию это свойство установлено в член перечисления AspectFit, но может быть установлено в любой из членов перечисления Aspect:
- AspectFit указывает, что при необходимости видео будет переведено в формат letterbox, чтобы вписаться в область отображения с сохранением соотношения сторон.
- AspectFill указывает, что видео будет обрезано так, чтобы оно заполнило область отображения с сохранением соотношения сторон.
- Fill указывает, что видео будет растянуто, чтобы заполнить область дисплея.
Привязка к свойству Position
Уведомления об изменении свойства Position срабатывают с интервалом 200 мс во время воспроизведения. Поэтому это свойство может быть привязано к элементу управления Slider (или аналогичному) для отображения прогресса в воспроизведении. CommunityToolkit также предоставляет конвертер TimeSpanToDoubleConverter, который преобразует TimeSpan в значение с плавающей точкой, представляющее общее количество прошедших секунд. Таким образом, вы можете установить максимальное значение ползунка на длительность медиафайла, а значение – на позицию, чтобы обеспечить точный прогресс:
<?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 ползунка привязано к свойству Duration элемента MediaElement, а свойство Value для Slider привязано к свойству Position элемента MediaElement. Поэтому перетаскивание Slider приводит к изменению позиции воспроизведения медиафайла:
Примечание. В ОС Android ползунок имеет только 1000 дискретных шагов, независимо от настроек Minimum и Maximum. Если длительность медиафайла больше 1000 секунд, то одному и тому же значению слайдера будут соответствовать два разных значения Position. Поэтому в приведенном выше коде проверяется, что новая позиция и существующая позиция больше одной сотой общей длительности.
Общие сведения о MediaSource
MediaElement может воспроизводить медиафайлы, установив в свойстве Source удаленный или локальный медиафайл. Свойство Source имеет тип MediaSource, и этот класс определяет два статических метода:
- FromFile - возвращает экземпляр MediaSource из строкового аргумента.
- FromUri - возвращает экземпляр MediaSource из аргумента Uri.
Кроме того, класс MediaSource имеет неявные операторы, возвращающие экземпляры MediaSource из аргументов string и Uri.
Примечание. Если в XAML задано свойство Source, то для возврата экземпляра MediaSource из строки или Uri вызывается преобразователь типов.
Класс MediaSource также имеет два производных класса:
- UriMediaSource, который используется для указания удаленного медиафайла из URI. Этот класс имеет свойство Uri, которое может быть установлено в Uri.
- FileMediaSource, который используется для указания локального медиафайла из строки. Этот класс имеет свойство File, которое может быть установлено в строку. Кроме того, в этом классе имеются неявные операторы для преобразования строки в объект FileMediaSource и объекта FileMediaSource в строку.
Примечание. При создании объекта FileMediaSource в XAML для возврата экземпляра FileMediaSource из строки вызывается конвертер типов.
Определение состояния MediaElement
Класс MediaElement определяет привязываемое свойство CurrentState типа MediaElementState, доступное только для чтения. Это свойство указывает на текущее состояние элемента управления, например, воспроизводится ли медиафайл, приостановлен ли он или еще не готов к воспроизведению медиафайла.
Перечисление MediaElementState определяет следующие члены:
- Closed означает, что MediaElement не содержит медиаданных.
- Opening указывает на то, что MediaElement проверяет и пытается загрузить указанный источник.
- Buffering указывает на то, что MediaElement загружает медиафайл для воспроизведения. В этом состоянии его свойство Position не продвигается. Если MediaElement воспроизводил видео, то он продолжает отображать последний показанный кадр. Воспроизведение указывает на то, что MediaElement воспроизводит медиаисточник.
- Paused указывает на то, что MediaElement не продвигает свое свойство Position. Если MediaElement воспроизводил видео, то он продолжает отображать текущий кадр.
- Stopped указывает на то, что MediaElement содержит медиаданные, но они не воспроизводятся и не приостановлены. Его свойство Position равно 0 и не продвигается. Если загруженный носитель - видео, то MediaElement отображает первый кадр.
При использовании элементов управления транспортировкой MediaElement обычно нет необходимости проверять свойство CurrentState. Однако это свойство становится важным при реализации собственных элементов управления транспортировкой.
Реализация пользовательских элементов управления транспортировкой
К элементам управления транспортом медиаплеера относятся кнопки, выполняющие функции Play, Pause и Stop. Эти кнопки обычно обозначаются привычными пиктограммами, а не текстом, а функции Play и Pause обычно объединяются в одну кнопку.
По умолчанию элементы управления воспроизведением медиаэлемента отключены. Это позволяет управлять MediaElement программно или с помощью собственных элементов управления транспортом. Для этого в MediaElement предусмотрены методы Play, Pause и Stop.
В следующем примере 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="▶️ Play" HorizontalOptions="CenterAndExpand" Clicked="OnPlayPauseButtonClicked"> <Button.Triggers> <DataTrigger TargetType="Button" Binding="{Binding CurrentState}" Value="{x:Static MediaElementState.Playing}"> <Setter Property="Text" Value="⏸ Pause" /> </DataTrigger> <DataTrigger TargetType="Button" Binding="{Binding CurrentState}" Value="{x:Static MediaElementState.Buffering}"> <Setter Property="IsEnabled" Value="False" /> </DataTrigger> </Button.Triggers> </Button> <Button Text="⏹ 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 всего два: первая кнопка представляет собой Play и Pause, а вторая – Stop. Для включения и выключения кнопок, а также для переключения первой кнопки между Play и Pause используются объекты DataTrigger.
В файле code-behind содержатся обработчики событий 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(); }
Для начала воспроизведения можно нажать кнопку Play, как только она станет активной:
Нажатие кнопки Pause приводит к приостановке воспроизведения:
Нажатие кнопки Stop останавливает воспроизведение и возвращает позицию медиафайла в начало.
Реализация пользовательского регулятора громкости
Элементы управления воспроизведением мультимедиа, реализованные в каждой платформе, содержат полосу громкости. Эта полоса напоминает ползунок и показывает громкость медиафайла. Кроме того, можно манипулировать полосой громкости для увеличения или уменьшения громкости.
Пользовательская панель громкости может быть реализована с помощью слайдера, как показано в следующем примере:
<StackLayout> <MediaElement AutoPlay="False" Source="{StaticResource AdvancedAsync}" /> <Slider Maximum="1.0" Minimum="0.0" Value="{Binding Volume}" Rotation="270" WidthRequest="100" /> </StackLayout>
В этом примере данные Slider связывают свое свойство Value со свойством Volume элемента MediaElement. Это возможно благодаря тому, что свойство Volume использует двухстороннюю привязку. Поэтому изменение свойства Value приведет к изменению свойства Volume.
Примечание. Свойство Volume имеет обратный вызов проверки, который гарантирует, что его значение больше или равно 0,0 и меньше или равно 1,0.
- Воспроизведение удаленных медиафайлов
- Воспроизведение локальных медиафайлов
- Воспроизведение медиафайлов, встроенных в пакет приложения
- Воспроизведение медиафайлов из локальных и временных папок приложения
- Копирование медиафайла в локальную или временную папку данных приложения
- Воспроизведение мультимедиа из библиотеки устройства
- Изменение соотношения сторон видео
- Привязка к свойству Position
- Общие сведения о MediaSource
- Определение состояния MediaElement
- Реализация пользовательских элементов управления транспортировкой
- Реализация пользовательского регулятора громкости