Работа с мультимедиа

Последнее обновление: 1.11.2015

Одной из сильных сторон технологии Silverlight является работа с мультимедиа - с аудио и видеоресурсами.

Элемент MediaElement

За воспроизведение аудио и видеоресурсов отвечает элемент MediaElement:

<MediaElement x:Name="media1" Source="Video.mp4" Width="300" Height="250" AutoPlay="True" />

Этот элемент имеет следующие полезные свойства:

  • Source - представляет свойство типа Uri и принимает в качестве значения имя ресурса. Здесь мы передаем либо имя файла, который может находиться у нас в ресурсах, либо, например, имя веб-ресурса, который мы собираемся воспроизвести

  • AutoPlay показывает, должен ли ресурс воспроизводиться автоматически

  • Height/Width - высота и ширина области видео, если эти свойства не заданы, то содержимое автоматически растягивается до размеров родительского контейнера

  • Stretch определяет форму растяжения элемента в родительском контейнере. По умолчанию имеет значение Fill.

  • Volume определяет громкость воспроизводимого. Принимает значений от 0 до 1, где 1 - это самый громкий уровень.

  • Balance определяет баланс между правым и левым динамиком. Принимает значений от -1 до 1, где при 1 звук идет только на правый динамик, а при -1 - только на левый динамик. При значении 0 звук распределяется между динамиками равномерно.

  • Position предоставляет объект TimeSpan, который указывает на текущее положение в файле - то есть на время.

С помощью метод Play, Pause и Stop мы можем управлять воспроизведением содержимого. Например, добавим на форму три кнопки - по одной для каждого метода. Мы могли бы создать две строки и три колонки в элементе Grid, чтобы управлять размещением элементов. Однако сейчас мы разместим кнопки поверж элемента MediaElement. Разметка xaml у нас будет выглядеть следующим образом:

    <Grid x:Name="LayoutRoot">
        <MediaElement x:Name="media1" Source="Video.mp4" AutoPlay="False" />
        <Button x:Name="playButton" Content="Play" Click="playButton_Click" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="60" Height="25"/>
        <Button x:Name="pauseButton" Content="Pause" Click="pauseButton_Click"  VerticalAlignment="Bottom" HorizontalAlignment="Center" Width="60" Height="25"/>
        <Button x:Name="stopButton" Content="Stop" Click="stopButton_Click"  VerticalAlignment="Bottom" HorizontalAlignment="Right" Width="60" Height="25" />
    </Grid>

А в файле кода определим обработчики для кнопок:

	    private void playButton_Click(object sender, RoutedEventArgs e)
        {
            media1.Play();
        }

        private void pauseButton_Click(object sender, RoutedEventArgs e)
        {
            media1.Pause();
        }

        private void stopButton_Click(object sender, RoutedEventArgs e)
        {
            media1.Stop();
        }

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

Теперь немного усложним приложение, добавив в него настройку звука и контроль за временем воспроизведения. Для этого добавим несколько новых элементов: три элемента Slider и два элемента TextBlock. Общий код xaml будет выглядеть следующим образом:

  <Grid x:Name="LayoutRoot">
        <MediaElement x:Name="media1" Stretch="UniformToFill"  Source="office_3.wmv" AutoPlay="False" MediaOpened="media1_MediaOpened" />
        <Button x:Name="playButton" Content="Play" Click="playButton_Click" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="40" Height="25"/>
        <Button x:Name="pauseButton" Content="Pause" Click="pauseButton_Click"  VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="40" Height="25" Margin="40 0 0 0"/>
        <Button x:Name="stopButton" Content="Stop" Click="stopButton_Click"  VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="40" Height="25" Margin="80 0 0 0" />
        <TextBlock Text="Громкость" VerticalAlignment="Bottom" HorizontalAlignment="Left" Margin="130 0 0 0" />
        <Slider x:Name="slider1" Height="20" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="100"  Margin="200 0 0 0" Minimum="0" Maximum="1" Value="0.5" ValueChanged="slider1_ValueChanged" />
        <Slider x:Name="slider2" Height="20" VerticalAlignment="Bottom" Margin="0 0 0 30"  ValueChanged="slider2_ValueChanged"  Opacity="0.5" />
        <Slider x:Name="sliderback2" Height="20" VerticalAlignment="Bottom" Margin="0 0 0 30"  IsHitTestVisible="False" />
        <TextBlock x:Name="time" Text="00:00" VerticalAlignment="Top"  />
    </Grid>

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

    public partial class MainPage : UserControl
    {
        DispatcherTimer timer = new DispatcherTimer();
        public MainPage()
        {
            InitializeComponent();
            timer.Interval = TimeSpan.FromSeconds(0.1);
            timer.Tick += timer_tick;
        }
        
        private void timer_tick(object sender, EventArgs e)
        {
            time.Text = media1.Position.ToString(@"mm\:ss");
            sliderback2.Value = media1.Position.TotalSeconds;
        }

        private void playButton_Click(object sender, RoutedEventArgs e)
        {
            media1.Play();
            timer.Start();
        }

        private void pauseButton_Click(object sender, RoutedEventArgs e)
        {
            media1.Pause();
            timer.Stop();
        }

        private void stopButton_Click(object sender, RoutedEventArgs e)
        {
            media1.Stop();
            timer.Stop();
        }

        private void media1_MediaOpened(object sender, RoutedEventArgs e)
        {
            slider2.Maximum = media1.NaturalDuration.TimeSpan.TotalSeconds;
            sliderback2.Maximum = media1.NaturalDuration.TimeSpan.TotalSeconds;
        }

        private void slider1_ValueChanged(object sender, RoutedPropertyChangedEventArgs e)
        {
            if (media1 != null)
            {
                media1.Volume = slider1.Value;
            }
        }

        private void slider2_ValueChanged(object sender, RoutedPropertyChangedEventArgs e)
        {
            media1.Pause();
            media1.Position = TimeSpan.FromSeconds(slider2.Value);
            media1.Play();
        }  
    }

Здесь в общем все понятно: сначала мы создаем объект таймера и прописываем некоторую дополнительную логику, связанную с изменением времени. Но возникает вопрос: зачем нам два ползунка? К сожалению не все так просто. Если бы мы использовали один ползунок, то при изменении времени таймера значению ползунка присваивалось значение позиции в элементе MediaElement, но при этом шло бы изменение значение ползунка, что в свою очередь изменяло текущую позицию элемента MediaElement, в итоге получалось бы отбрасывание назад. Поэтому в данном случае решение с двумя ползунками является самым простым. Однако это не значит, что мы не могли бы использовать только один ползунок. Просто в этом случае решение выглядело бы сложнее. Кроме того, мы могли бы использовать интеграцию с JavaScript и элементами HTML веб-страницы, что также могло в некотором плане облегчить написание плейера, но про интеграцию мы поговорим в следующих главах. А сейчас мы можем использовать уже имеющийся плейер:

Поддерживаемые аудиоформаты

Список поддерживаемых форматов для аудио:

  • Wav

  • Windows Media Audio (wma) - версии 7,8,9

  • MP3 с фиксированной или перемнной скоростью передачи данных 8-320 кБит/сек

Поддерживаемые видеоформаты:

  • Windows Media Video (wmv) - версии 7,8,9

  • Windows Media Video Advanced Profile, non-VC-1 (wmva)

  • Windows Media Video Advanced Profile, VC-1 (wmvc1)

  • H.264 для видео и AAC для аудио (также известен как формат MPEG-4 Part 10 или MPEG-4 AVC) - контейнер mp4

Также стоит сказать, что Silverlight поддерживает как воспроизведение отдельных непотоковых файлов, так и потоковую передачу по протоколам http, mms, rtsp.

Работа с маркерами

Медиафайл может обладать маркерами. Маркеры представляют некоторые метаданные или аннотации, ассоциированные с определенной временной точкой файла. Такие маркеры очень удобны для создания субтитров.

Когда при воспроизведении файла поток доходит до маркера, то элемент MediaElement генерирует событие MarkerReached. Чтобы использовать маркеры, изменим предыдущее приложение. Вначале нам надо где-то выводить текст маркеров. Для этого добавим еще один элемент TextBlock, который будет располагаться над ползунком времени. А также изменим код элемента MediaElement:

	.........
    <MediaElement x:Name="media1" Stretch="UniformToFill"  Source="office_3.wmv" AutoPlay="False" MediaOpened="media1_MediaOpened" MarkerReached="media1_MarkerReached" />
    <TextBlock x:Name="markerBlock" Width="300" Height="40" TextWrapping="Wrap" FontSize="14" VerticalAlignment="Bottom" Margin="0 0 0 50" />
    .........

Теперь в файле кода добавим соответствующий обработчик событий:

	    private void media1_MarkerReached(object sender, TimelineMarkerRoutedEventArgs e)
        {
            markerBlock.Text = e.Marker.Text;
        }

Здесь мы получаем текст маркера и присваиваем его значение свойству Text нашего нового элемента TextBlock. И теперь, если в медиафайле есть какие-нибудь маркеры. мы можем запустить приложение. Однако в моем файле не оказалось маркеров.

Как добавить маркеры? Это можно сделать, например, с помощью программы Microsoft Expression Media Encoder. В этом случае мы добавляем маркеры напрямую в файл.

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

Итак, каждый маркер представляет собой объект TimelineMarker. Чтобы этот объект можно было использовать, для него надо определить временную точку с помощью свойства Time и определить текст маркера с помощью свойства Text. Также можно определить свойство Type. И в конце добавить новый маркер в коллекцию Markers элемента MediaElement. Итак, добавим в код три маркера и инициализируем их в конструкторе окна:

        TimelineMarker marker1,marker2,marker3;
        public MainPage()
        {
            InitializeComponent();
            timer.Interval = TimeSpan.FromSeconds(0.1);
            timer.Tick += timer_tick;

            marker1 = new TimelineMarker();
            marker1.Text = "На мониторе исходный код программы";
            marker1.Time = new TimeSpan(0,0,54);
            marker2 = new TimelineMarker();
            marker2.Text = "Фильм Офис-3";
            marker2.Time = new TimeSpan(0, 0,0);
            marker3 = new TimelineMarker();
            marker3.Text = "";
            marker3.Time = new TimeSpan(0, 0, 8);
        }

Теперь добавим их к MediaElement в обработчике события MediaOpened - то есть в процедуре media1_MediaOpened:

private void media1_MediaOpened(object sender, RoutedEventArgs e)
        {
            slider2.Maximum = media1.NaturalDuration.TimeSpan.TotalSeconds;
            sliderback2.Maximum = media1.NaturalDuration.TimeSpan.TotalSeconds;
            media1.Markers.Add(marker1);
            media1.Markers.Add(marker2);
            media1.Markers.Add(marker3);
        }

После запуска приложения в процессе просмотра наши маркеры будут отображаться в элементе TextBlock именно на тех временных отрезках, на которых они определены:

Использование кисти VideoBrush

Говоря о кистях, мы не затрагивали такую кисть, как VideoBrush. Эта кисть принимает в качестве источника некоторый медиаконтент и его отрисовывет на элементе. Итак, используем кисть VideoBrush:

	<MediaElement x:Name="media1" Source="office_3.wmv" Width="0" Height="0" />
        <Ellipse Width="250" Height="200" VerticalAlignment="Center">
            <Ellipse.Fill>
                <VideoBrush SourceName="media1" />
            </Ellipse.Fill>
        </Ellipse>

Здесь мы создаем элемент MediaElement с нулевыми размерами, и затем создаем элемент Ellipse, чей фон задается кистью VideoBrush. Эта кисть в качестве источника принимает ранее созданный MediaElement. Теперь после запуска приложения и соответственно после запуска воспроизведения в MediaElement мы увидим весь воспроизводимый контент на элементе Ellipse:

В данном случае мы могли использовать любой элемент, а также могли установить VideoBrush не только для свойства Fill или Background, но и для свойства Foreground. Кроме того, для элементов управления содержимым, как, например, элемент Button, мы можем просто встроить MediaElement в свойство Content и таким образом обойтись без VideoBrush.

К элементу VideoBrush также могут применяться трансформации. Например, сужение по оси Х:

			<VideoBrush SourceName="media1">
				<VideoBrush.RelativeTransform>
					<ScaleTransform ScaleX="0.5" />
				</VideoBrush.RelativeTransform>
			</VideoBrush>
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850