Главная » C#, Windows Runtime, XAML, Разработка для Windows 8 » Работа с аудио и видео Windows Runtime

0

Введение в MediaElement

Общие сведения

Если Вы работали с Silverlight или Windows Presentation Foundation, то в первой части  этой  главы найдете  знакомый  материал.  Ведь   элемент   управления MediaElement был основой для построения всех интерфейсов, поддерживающих отображение видео или только аудио. В Windows Runtime этот элемент выполняет аналогичные функции, и механизм работы с ним практически тот же.

В WinRT, как  и  в   Silverlight, MediaElement поддерживает ряд  форматов  для отображения видео и проигрывания аудио. Вот эти форматы:

·                   WMV1: Windows Media Video 7;

·                   WMV2: Windows Media Video 8;

·                   WMV3: Windows Media Video 9;

·                   WMVA: Windows Media Video Advanced Profile, non-VC-1;

·                   WVC1: Windows Media Video Advanced Profile, VC-1;

·                   H.264;

·                   Поддержка видео в формате 3D (функция, отсутствующая в Silverlight).

Если Ваше видео в  другом формате, его необходимо преобразовать в один из поддерживаемых форматов с помощью одной из утилит, например Expression Encoder.

Рассмотрим, какие форматы поддерживаются для аудио:

·                   WAV;

·                   WMA7: Windows Media Audio 7;

·                   WMA8: Windows Media Audio 8;

·                   WMA9: Windows Media Audio 9;

·                   WMA10: Windows Media Audio 10;

·                   MP3: ISO/MPEG-1 Layer 3;

·                   AAC.

И, наконец, если говорить о протоколах, которые поддерживает MediaElement, то это http, https и mms. Последний из протоколов использует Windows Media Service для трансляции потокового видео. В зависимости от указанного протокола MediaElement пытается выполнить или прогрессивную, или потоковую загрузку.

Если Вы указываете протокол http или https, то сначала производится попытка выполнить прогрессивную загрузку, а в  случае неудачи — потоковую. Если же вы указываете  протокол mms, то первой будет попытка выполнить потоковую загрузку.

Естественно, MediaElement можно с успехом использовать и для отображения видео из локального хранилища или пакета приложения.

В    иерархии    классов   MediaElement    является   прямым     наследником FrameworkElement.  Это  означает,  что  он  обладает  большинством свойств, характерных для других элементов управления. Но несколько свойств характерны только для этого элемента. Рассмотрим эти свойства:

·                   Source —  позволяет установить путь к  видеофайлу (потоку),  который должен быть отображен в MediaElement. Кроме этого свойства существует метод SetSource, о котором будет сказано ниже;

·                   AutoPlay — позволяет указать, нужно ли проигрывать указанный видео или аудио сразу после загрузки приложения. По умолчанию это свойство установлено в true. Между тем, если Ваш видео или аудио не передается вместе с приложением, лучше установить значение в false;

·                   IsMuted — позволяет отключить звук, если свойство установлено в true;

·                   Volume  —  задает  текущий  уровень громкости.  Значение   громкости варьируется от  0  до  1.  По  умолчанию  значение  установлено в   0,5. Поэтому если Ваш интерфейс не предоставляет механизма регулирования громкости, установите Volume в  1. В противном случае получите много отзывов о том, что слишком тихо;

·                   Balance — принимает значения в  диапазоне от -1 до 1. По умолчанию это свойство установлено  в 0, что гарантирует одинаковый баланс между правым и левым аудиовыходом.  Если значение установлено в -1, то весь звук будет направлен на левую колонку, а если +1, то на правую;

·                   Position — содержит текущую позицию в  отображаемом  видеофайле.

Чтобы   установить  или   получить   свойство Position,    необходимо использовать тип  TimeSpan,  который  задает  время в   часах,  минутах и секундах;

·                   CanSeek — позволяет определить, возможно ли использовать свойство Position для перемещения по видео. Ведь если MediaElement принимает потоковое видео, то ни о каком перемещении не может быть и речи;

·                   CanPause  —  определяет,  можно  ли  приостановить  воспроизведение контента. Если передается потоковое видео, то возвращает значение false;

·                   CurrentState — определяет состояние медиаэлемента и может содержать одно из значений перечислимого типа  MediaElementState: Buffering, Opening, Playing, Closed, Paused, Stopped;

·                   DownloadProgress  —   определяет   процент   контента,   загруженного с сервера. Это свойство применимо при  прогрессивной загрузке, когда файл с контентом загружается с сервера;

·                   DownloadProgressOffset — определяет смещение (позицию), с которого начинается загрузка фрагмента видео. Данное свойство устанавливается в том случае, если пользователь изменил текущую позицию на фрагмент, который еще не был загружен;

·                   DroppedFramesPerSecond — показывает количество фреймов в секунду, которые были выброшены из потока из-за невозможности их отобразить. Используется для потокового видео;

·                   Markers — содержит коллекцию маркеров, которые содержатся в видео.

О маркерах будет сказано в следующем разделе;

·                   NaturalDuration — определяет общую продолжительность  видео- или аудиофрагмента.  Свойство задается  с  помощью   экземпляра  класса TimeSpan;

·                   NaturalVideoWidth — это свойство, а также свойство NaturalVideoHeight,

задают исходную длину и ширину видео;

·                   NaturalVideoHeight — возвращает исходную ширину видео.

Пример использования MediaElement:

<Grid Background="{StaticResource ApplicationPageBackgroundBrush}">

<Grid x:Name="LayoutRoot" Background="Gray" Width="400" Height="400">

<MediaElement Source="WildLife.wmv"></MediaElement>

</Grid>

</Grid>

Тут мы специально установили явные размеры родительского элемента и серый фон. Запустив это приложение, Вы сможете увидеть такую картину:

Рис. 9.1.

Как видите, несмотря на то, что у данного изображения достаточно  высокое разрешение,  оно  было  ужато  до  размеров медиаэлемента  с  сохранением пропорций. При этом в MediaElement могут быть незаполненные участки.

В  дополнение к  рассмотренным свойствам  можно  выделить свойство  Clip. Свойство может содержать любую геометрию, создавая  причудливые формы, заполненные видео.

Разобравшись со  свойствами  MediaElement,  рассмотрим  основные  методы,

позволяющие управлять видео:

·                   SetSource —  метод  SetSource позволяет установить свойство  Source

медиаэлемента;

·                   Play  —  запускает  видео или  аудио  для  проигрывания. Если   видео передается в виде  потока, то просто начинает выбирать данные из потока;

·                   Pause — останавливает проигрывание  контента. Если видео передается в виде  потока, то вызов метода будет проигнорирован;

·                   Stop — останавливает воспроизведение.

И, наконец, самое важное, — это события, которые связаны с  MediaElement. Ведь именно реакция на события позволит сделать  Ваш интерфейс наиболее динамичным и привлекательным для  пользователя.  Рассмотрим все  события, характерные для медиаэлемента:

·                   BufferingProgressChanged  —  генерируется  при  изменении   свойства BufferingChanged,  то  есть  при  буферизации   очередного  фрагмента видео;

·                   CurrentStateChanged   —   генерируется   при   изменении    состояния медиаэлемента;

·                   DownloadProgressChanged —  генерируется при  изменении  процента загрузки видео с сервера;

·                   MarkerReached —  генерируется  тогда,  когда  был  достигнут  один  из маркеров, установленных внутри   видео. О  маркерах   будет  сказано в следующем разделе;

·                   MediaEnded — событие происходит тогда, когда медиаэлемент прекратил проигрывать видео или аудио;

·                   MediaFailed — важное событие, так как именно оно позволяет реагировать на ошибки, связанные с чтением медиаконтента, в  управляемом  коде. Если обработчик на это событие не найден,  то ошибка будет передана в JavaScript, а приложение прекратит свою работу;

·                   MediaOpened  —  происходит, когда  медиапоток  был  успешно  открыт и была получена начальная информация о нем.

Рассмотрев такое количество свойств, методов и событий, можно сделать вывод, что MediaElement обладает всем необходимым для  реализации  интерфейса любой сложности. Давайте рассмотрим небольшой пример, демонстрирующий некоторые свойства, события и методы медиаэлемента.

Реализуем интерфейс нашего приложения следующим образом:

<StackPanel HorozontalAlignment="Left">

<MediaElement Name="myMedia" Height="300" Source="WildLife.wmv"

Margin="5" AutoPlay="False" MediaOpened="myMedia_MediaOpened" MediaEnded="myMedia_MediaEnded">

</MediaElement>

<StackPanel Orientation="Horizontal">

<TextBlock Name="durationText" Text="Duration: " Margin="5">

</TextBlock>

<TextBlock Text=

"{Binding Position.TotalSeconds, ElementName=myMedia, Mode=OneWay}"

Margin="5">

</TextBlock>

<TextBlock Text="/" Margin="5"></TextBlock>

<TextBlock Text="" Name="secondsText" Margin="5">

</TextBlock>

</StackPanel>

<Slider Name="positionSlider" Minimum="0" Margin="5" IsEnabled="False"

Value=

"{Binding Position.TotalSeconds, ElementName=myMedia, Mode=OneWay}"

</Slider>

<StackPanel Orientation="Horizontal" >

<Button Content="Play" Name="playButton" Margin="5" Width="100" IsEnabled="False" Click="playButton_Click"></Button>

<Button Content="Pause" Name="pauseButton" IsEnabled="False" Margin="5" Width="100" Click="pauseButton_Click" ></Button>

<Button Content="Stop" Name="stopButton" Margin="5" Width="100" IsEnabled="False" Click="stopButton_Click" ></Button>

<CheckBox Content="Mute" Margin="5" IsEnabled="False" Name="muteBox" IsChecked=

"{Binding IsMuted, ElementName=myMedia, Mode=TwoWay}"

</CheckBox>

</StackPanel>

<StackPanel Orientation="Horizontal" >

<TextBlock Text="Volume:" Margin="5"></TextBlock>

<Slider Name="volumeSlider" Minimum="0" Maximum="1" Width="200" IsEnabled="False" StepFrequency="0.1" Value=

"{Binding Volume, ElementName=myMedia, Mode=TwoWay}">

</Slider>

</StackPanel>

</StackPanel>

Тут мы создали медиаэлемент и  множество элементов  управления,  которые позволят отображать текущую  позицию,  изменять  громкость,  останавливать отображение видео и др.

Вот как должен выглядеть наш интерфейс:

Рис. 9.2.

Большинство элементов  мы  установили с  помощью  механизма  связывания с данными, но какой-то код нам придется написать. Вот как будут выглядеть наши обработчики событий:

private void myMedia_MediaOpened(object sender, RoutedEventArgs e)

{

positionSlider.IsEnabled = true; volumeSlider.IsEnabled = true; playButton.IsEnabled = true; stopButton.IsEnabled = true;

positionSlider.Maximum = myMedia.NaturalDuration.TimeSpan.TotalSeconds;

secondsText.Text = myMedia.NaturalDuration.ToString();

}

private void playButton_Click(object sender, RoutedEventArgs e)

{

playButton.IsEnabled = false; pauseButton.IsEnabled = true;

myMedia.Play();

}

private void pauseButton_Click(object sender, RoutedEventArgs e)

{

pauseButton.IsEnabled = false; playButton.IsEnabled = true;

myMedia.Pause();

}

private void stopButton_Click(object sender, RoutedEventArgs e)

{

pauseButton.IsEnabled = false; playButton.IsEnabled = true;

myMedia.Stop();

}

private void myMedia_MediaEnded(object sender, RoutedEventArgs e)

{

pauseButton.IsEnabled = false; playButton.IsEnabled = true;

}

В этих обработчиках событий мы вызываем соответствующие  методы  (Stop, Start, Pause) и активируем кнопки, которые должны быть доступны исходя из логики интерфейса.

Как видно, реализовать  полноценный медиаплейер не очень сложно.  Больше времени уйдет на дизайн интерфейса. Естественно, если вы хотите реализовать универсальный плейер, который будет проигрывать и потоковое видео, придётся добавить дополнительные проверки. Однако идея от этого не изменится.

Рассмотрим еще одну особенность медиаэлемента — маркеры.

Использование маркеров

Маркеры представляют собой специальные метки, привязанные к конкретной точке на временной шкале видео. Эти метки способны содержать данные (текст) и могут быть созданы либо с помощью Microsoft Expression Encoder (тогда они сохраняются в видеофайле), либо динамически (такие метки сохраняются лишь в памяти).

Сценариев применения  маркеров много.  Например,  маркеры   могут   быть использованы для создания обучающих уроков, когда в процессе отображения видео необходимо пройти промежуточные тесты или запустить анимацию.

Еще   один   пример   —   это   управление  субтитрами.   Фактически,    чтобы ассоциировать субтитры с видео, достаточно создать коллекцию маркеров и при достижении очередного маркера (событие MarkerReached) отобразить субтитр на экран. Покажем использование маркеров на примере сценария с субтитрами.

Создадим   простое   приложение,   содержащее   медиаэлемент   и   поле   для отображения субтитров:

<StackPanel>

<MediaElement Width="400" Height="300" Name="myMedia" Source="Wildlife.wmv" MediaOpened="myMedia_MediaOpened" MarkerReached="myMedia_MarkerReached">

</MediaElement>

<TextBlock Text="" HorizontalAlignment="Center" Name="subtitleText" FontSize="16" FontWeight="Bold" >

</TextBlock>

</StackPanel>

Было бы хорошо выбирать субтитры из XML или текстового файла. Но  чтобы не писать много кода, просто создадим несколько экземпляров класса Subtitle, который  мы  определили  самостоятельно.   Экземпляры  этого  класса  будут содержать время и сам текст субтитров.

Заполнение коллекции маркеров должно произойти после успешной загрузки видео, а  при  достижении  очередного  маркера  мы   просто   выдаем текст, хранящийся в нем. Вот как выглядит код:

public sealed partial class BlankPage : Page

{

Subtitle[] subtitles = new Subtitle [3];

public BlankPage()

{

InitializeComponent();

Subtitle s=new Subtitle(); s.text = "Побежали лошадки"; s.time = new TimeSpan(0, 0, 0); subtitles[0] = s;

s = new Subtitle();

s.text = "Полетели птички"; s.time = new TimeSpan(0, 0, 5); subtitles[1] = s;

s = new Subtitle();

s.text = "Суслики на пляже"; s.time = new TimeSpan(0, 0, 7); subtitles[2] = s;

}

private void myMedia_MediaOpened(object sender, RoutedEventArgs e)

{

TimelineMarker t;

foreach (Subtitle s in subtitles)

{

t = new TimelineMarker(); t.Time = s.time;

t.Text = s.text; myMedia.Markers.Add(t);

}

}

private void myMedia_MarkerReached(object sender, TimelineMarkerRoutedEventArgs e)

{

subtitleText.Text = e.Marker.Text;

}

}

class Subtitle

{

public TimeSpan time; public String text;

}

Результат работы приложения показан на рисунке.

Рис. 9.3.

Таким образом, работа с маркерами не представляет сложностей. Вместе с тем,

маркеры являются мощным инструментом при работе с видео.

Сергей Лутай, Сергей Байдачный, Windows 8 для C# разработчиков

По теме:

  • Комментарии