旅行好きなソフトエンジニアの備忘録

プログラミングや技術関連のメモを始めました

【WPF】 簡易動画プレーヤーを作成する

今回は動画のプレーヤーを作ってみます(簡易的なものですが)。調べてみるとWPFにはMediaElementというものがあって、これを使ってみると良さそうです。
まずはxamlが以下のようになります。

<Window x:Class="CSMediaPlayer.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:CSMediaPlayer"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="6*"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
        <MediaElement Name="MediaElementMovie" Grid.Row="0" Stretch="Fill" LoadedBehavior="Manual" UnloadedBehavior="Manual"/>
        <Grid Grid.Row="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="1*"/>
                <ColumnDefinition Width="1*"/>
                <ColumnDefinition Width="1*"/>
                <ColumnDefinition Width="4*"/>
            </Grid.ColumnDefinitions>
            <Button Name="ButtonPlay" Grid.Column="0" Content="▶" Click="ButtonPlay_Click"/>
            <Button Name="ButtonPause" Grid.Column="1" Content="||" Click="ButtonPause_Click"/>
            <Button Name="ButtonStop" Grid.Column="2" Content="■" Click="ButtonStop_Click"/>
            <Grid Grid.Column="3">
                <Slider Name="SliderMoviePosition" VerticalAlignment="Center" Minimum="0" Maximum="100" ValueChanged="SliderMoviePosition_ValueChanged"/>
            </Grid>
        </Grid>
    </Grid>
</Window>

上記のXAMLでこんな感じの見た目になります。あとはボタンやスライダーにイベントを割り振っていきます。
f:id:ni4muraano:20170730170109p:plain

using System;
using System.Windows;
using System.Windows.Threading;

namespace CSMediaPlayer
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        // 動画の相対パス
        private readonly string _videoPath = "video.avi";
        // スライダーを動かすためのタイマー
        private DispatcherTimer _timer = new DispatcherTimer();
        // タイマー起動間隔(1秒)
        private const int _timerInterval = 1;
        // 動画経過時間
        private int _elapsedSec = 0;
        // スライダーをユーザーが動かしたかどうか判別するフラグ
        private bool _sliderValueChangedByProgram = false;

        public MainWindow()
        {
            InitializeComponent();

            _timer.Interval = new TimeSpan(0, 0, _timerInterval);
            _timer.Tick += dispatcherTimer_Tick;
        }

        private void dispatcherTimer_Tick(object sender, EventArgs e)
        {
            // 動画経過時間に合わせてスライダーを動かす
            _elapsedSec += _timerInterval;
            double totalSec = MediaElementMovie.NaturalDuration.TimeSpan.TotalSeconds;
            SliderMoviePosition.Value = _elapsedSec / totalSec * SliderMoviePosition.Maximum;
            _sliderValueChangedByProgram = true;
        }

        private void ButtonPlay_Click(object sender, RoutedEventArgs e)
        {
            // 動画を再生
            _timer.Start();
            MediaElementMovie.Source = new Uri(_videoPath, UriKind.Relative);
            MediaElementMovie.Play();
        }

        private void ButtonPause_Click(object sender, RoutedEventArgs e)
        {
            // 動画を一次停止
            _timer.Stop();
            MediaElementMovie.Pause();
        }

        private void ButtonStop_Click(object sender, RoutedEventArgs e)
        {
            // 動画を停止
            _timer.Stop();
            _elapsedSec = 0;
            SliderMoviePosition.Value = 0;
            MediaElementMovie.Stop();
            MediaElementMovie.Source = null;
        }

        private void SliderMoviePosition_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (!_sliderValueChangedByProgram)
            {
                // スライダーを動かした位置に合わせて動画の再生箇所を更新する
                double totalSec = MediaElementMovie.NaturalDuration.TimeSpan.TotalSeconds;
                double sliderValue = SliderMoviePosition.Value;
                int targetSec = (int)(sliderValue * totalSec / SliderMoviePosition.Maximum);
                _elapsedSec = targetSec;
                TimeSpan ts = new TimeSpan(0, 0, 0, targetSec);
                MediaElementMovie.Position = ts;
            }
            _sliderValueChangedByProgram = false;
        }
    }
}


参考にしたサイトはここです(方法 : MediaElement (再生、一時停止、停止、ボリューム、および速度) を制御する )。サイトでは様々なイベントを定義しているので、きちんと作るのであれば上記コードは改善しないといけなさそうです。。。