Видео

37

Все, что было сказано о применении класса MediaElement, в равной степени касается и воспроизведения видеофайлов. Как и можно было ожидать, класс MediaElement поддерживает все видеоформаты, которые поддерживает проигрыватель Windows Media. Хотя поддержка и зависит от установленных кодеков, вполне можно рассчитывать на базовую поддержку форматов WMV, MPEG и AVI.

Ключевое отличие при воспроизведении видеофайлов заключается в том, что здесь становятся важными визуальные свойства MediaPlayer, а также свойства, касающиеся его компоновки. Важнее всего свойства Stretch и StretchDirection, определяющие, как масштабируется видео-окно для заполнения контейнера (эти свойства работают так же, как свойства Stretch и StretchDirection классов-наследников Shape). При установке значения Stretch можно использовать None для сохранения исходного размера, Uniform — чтобы растянуть его для заполнения контейнера без изменения пропорций, Fill — для растяжения по обоим измерениям до размеров контейнера (даже если это значит искажение пропорций) и UniformToFill — для растяжения изображения, чтобы оно уместилось в максимальное измерение контейнера, а пропорции сохранились (при этом, если пропорции видео-окна не будут совпадать с пропорциями контейнера, то часть видео-окна будет усечена).

Предпочтительный размер MediaElement основан на исходных пропорциях видео. Например, если создать MediaElement со значением Stretch, равным Uniform (по умолчанию так и есть) и поместить его внутрь строки Grid со свойством Height, установленным в Auto, то строка будет подогнана по размеру так, чтобы вместить видео в его стандартном размере, без масштабирования.

Видео-эффекты

Поскольку MediaElements работает как любой другой элемент WPF, есть возможность манипулировать им несколько неожиданным образом. Ниже описаны примеры:

Например, следующий код разметки создает эффект отражения. Он делает это посредством создания объекта Grid, состоящего из двух строк. Верхняя строка содержит MediaElement, воспроизводящий видеофайл. Нижняя строка содержит Rectangle, который рисуется с помощью VisualBrush. Трюк в том, что VisualBrush принимает свое содержимое от видео-окна, расположенного над ним, используя выражение привязки. Видео-содержимое затем опрокидывается с использованием RelativeTransform, а затем плавно затухает сверху вниз с помощью градиента OpacityMask:

<Grid Margin="15" HorizontalAlignment="Center">
    <Grid.RowDefinitions>      
      <RowDefinition Height="Auto"></RowDefinition>
      <RowDefinition></RowDefinition>
      <RowDefinition Height="Auto"></RowDefinition>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto"></ColumnDefinition>
    </Grid.ColumnDefinitions>

    <Border BorderBrush="DarkGray" BorderThickness="1" CornerRadius="2">
      <MediaElement x:Name="video" Source="test.mpg" LoadedBehavior="Manual" Stretch="Fill"></MediaElement>
    </Border>

    <Border Grid.Row="1" BorderBrush="DarkGray" BorderThickness="1" CornerRadius="2">
      <Rectangle VerticalAlignment="Stretch" Stretch="Uniform">
      <Rectangle.Fill>
        <VisualBrush Visual="{Binding ElementName=video}">
          <VisualBrush.RelativeTransform>
            <ScaleTransform ScaleY="-1" CenterY="0.5"></ScaleTransform>
          </VisualBrush.RelativeTransform>        
        </VisualBrush>
      </Rectangle.Fill>
      
      <Rectangle.OpacityMask>
        <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">          
          <GradientStop Color="Black" Offset="0"></GradientStop>
          <GradientStop Color="Transparent" Offset="0.6"></GradientStop>
        </LinearGradientBrush>
      </Rectangle.OpacityMask>
      </Rectangle>
    </Border>

      <Button Grid.Row="2" Padding="3" Click="cmdPlay_Click">Play</Button>
  </Grid>
Отражение видео

Этот пример работает очень хорошо. Эффект отражения влечет за собой те же накладные расходы, что и два видео-окна, поскольку каждый кадр должен копироваться в нижний прямоугольник. Вдобавок каждый кадр понадобится опрокинуть и добавить к нему затухание, чтобы создать эффект отражения. (Для выполнения таких трансформаций WPF использует промежуточную поверхность визуализации.) Но в современных компьютерах упомянутыми накладными расходами можно пренебречь.

Это не так в случае других видеоэффектов. Фактически видео — одна из немногих областей WPF, где очень легко перегрузить процессор и получить неважно работающий пользовательский интерфейс. Средние компьютеры не могут обрабатывать более чем несколько видео-окон одновременно (конечно, в зависимости от размеров видеофайла — более высокое разрешение и большая частота кадров, естественно, означает больший объем данных, на обработку которых требуется больше времени).

В WPF определен класс VideoDrawing, унаследованный от класса Drawing. VideoDrawing может применяться для создания кисти DrawingBrush, которая, в свою очередь, служит для заполнения поверхности элемента, создавая тот же эффект, что был продемонстрирован выше в примере с VisualBrush.

Однако есть одно отличие, которое может сделать подход с VideoDrawing более эффективным. Это связано с тем, что VideoDrawing использует класс MediaPlayer, в то время как подход на основе VisualBrush требует применения класса MediaElement. Класс MediaPlayer не нуждается в управлении компоновкой, фокусом или другими деталями элемента, поэтому он более легковесный, чем MediaElement. В некоторых ситуациях использование VideoDrawing и DrawingBrush вместо MediaElement и VisualBrush помогает избежать необходимости в промежуточной поверхности визуализации и за счет этого повышает производительность (хотя проведенное тестирование не позволило заметить существенную разницу между этими двумя подходами).

Пройди тесты
Лучший чат для C# программистов