WPF 入門:動画の再生方法 MediaElement【初心者講座】

WPFでMediaElementを使っての動画再生方法と簡単な動画プレイヤーのソースコードをご紹介します。

MediaElementの使い方

MediaElementを使ってウィンドウ上で動画を再生します。

プロジェクトを新規作成して、自動で生成されるMainWindow.xamlを編集していきます。

MediaElementの配置

ソリューションエクスプローラーの「MainWindow.xaml」をダブルクリックして、エディターに表示させます。
ツールボックスを展開して、「MediaElement」をウィンドウの中にドラッグ&ドロップで配置します。

MediaElementの配置

ウィンドウにMediaElementコントロールが追加されます。
また、ウィンドウの中にMediaElementを配置すると、画面下のXAMLにも同時にコードが追加されます。
配置した時のMediaElementのサイズは100×100と小さいので好みのサイズにリサイズします。

MediaElementのリサイズ

<MediaElement HorizontalAlignment="Left" Height="270" Margin="20,20,0,0" VerticalAlignment="Top" Width="480"/>

映像ソースの設定

「デザイン」ペインでMediaElementコントロールをクリックして選択状態にします。
そうすると、「プロパティ」ペインでMediaElementの各種設定情報を編集できるようになります。

MediaElementのプロパティを表示

「プロパティ」ペイン内の「メディア」を展開して、その中の「Source」の項目の「…」ボタンをクリックします。

MediaElementのソース変更

「…」ボタンをクリックすると、ファイル選択ダイアログが表示されます。
ファイルの種類のプルダウンから「ビデオファイル (*.avi;*.mpg;*.mpeg;*.mov;*.qt)」を選択してください。
この状態で上記の拡張子の動画ファイルが選択可能となりますので、再生したい動画を選択して「追加」をクリックしてください。
(ここでは、「sample.avi」を選択しました。)

ファイル選択ダイアログ

以下のように、MediaElementコントロールに先ほど選択した動画が表示されます。
また、同時にソリューションエクスプローラ上に「sample.avi」が追加され、XAMLのMediaElementにも「Source=”sample.avi”」が追加されます。

MediaElementのソースを設定
<MediaElement HorizontalAlignment="Left" Height="270" Margin="20,20,0,0" VerticalAlignment="Top" Width="480" Source="sample.avi"/>

ソリューションエクスプローラー上のソースファイル(sample.avi)をクリックしてください。
プロパティ > 出力ディレクトリにコピー の項目を「新しい場合はコピーする」に変更します。

出力ディレクトリにコピーを変更

実行画面

実行するとウィンドウ内で動画再生されることを確認できます。

MediaElementの表示

簡単な動画プレイヤーの実装

参考までに以下の画面のような簡単な動画プレイヤーのプログラムを記載します。

MediaElementで作った簡易動画プレイヤー

ソースコード MainWindow.xaml

<Window x:Class="WpfMovieSample.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:WpfMovieSample"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded">
    <Grid>
        <MediaElement x:Name="mediaElement" HorizontalAlignment="Left" Height="270" Margin="20,20,0,0" VerticalAlignment="Top" Width="480" Source="sample.avi" LoadedBehavior="Manual" MediaOpened="mediaElement_MediaOpened" MediaEnded="mediaElement_MediaEnded"/>
        <Slider Name="slider" VerticalAlignment="Top" HorizontalAlignment="Left" Minimum="0" Maximum="100" Margin="20,295,0,0" Height="23" Width="480"/>
        <Button Content="再生" HorizontalAlignment="Left" Margin="109,328,0,0" VerticalAlignment="Top" Width="99" Height="49" Click="ButtonClickPlay"/>
        <Button Content="一時停止" HorizontalAlignment="Left" Margin="213,328,0,0" VerticalAlignment="Top" Width="100" Height="49" Click="ButtonClickPause"/>
        <Button Content="停止" HorizontalAlignment="Left" Margin="318,328,0,0" VerticalAlignment="Top" Width="99" Height="49" Click="ButtonClickStop"/>
    </Grid>
</Window>

ソースコード MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace WpfMovieSample
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        /// <summary>
        /// スライダー更新用タイマー
        /// </summary>
        private DispatcherTimer m_timer;

        /// <summary>
        /// ユーザーの操作により設定中のステータス
        /// </summary>
        private MediaState m_stateCurrent;

        /// <summary>
        /// スライダー前回値
        /// </summary>
        private double m_dbLastSliderValue;

        //-------------------------------------------------------------

        /// <summary>
        /// MainWindow
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Loaded
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            // タイマー設定
            m_timer = new DispatcherTimer();
            m_timer.Interval = TimeSpan.FromMilliseconds(100);
            m_timer.Tick += dispatcherTimer_Tick;

            // MediaElementをロードさせる。
            mediaElement.Play();
            mediaElement.Stop();
        }

        /// <summary>
        /// タイマーイベント
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dispatcherTimer_Tick(object sender, EventArgs e)
        {
            SyncSliderAndSeek();
        }

        //--------------------------------------------------------------------
        // コントロールイベント
        //--------------------------------------------------------------------

        /// <summary>
        /// 再生ボタンクリック
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ButtonClickPlay(object sender, RoutedEventArgs e)
        {
            Play();
        }

        /// <summary>
        /// 一時停止ボタンクリック
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ButtonClickPause(object sender, RoutedEventArgs e)
        {
            Pause();
        }

        /// <summary>
        /// 停止ボタンクリック
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ButtonClickStop(object sender, RoutedEventArgs e)
        {
            Stop();
        }

        /// <summary>
        /// MediaElement オープン完了イベント
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mediaElement_MediaOpened(object sender, RoutedEventArgs e)
        {
            // タイマースタート
            m_timer.Start();
        }

        /// <summary>
        /// MediaElement 再生完了イベント
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mediaElement_MediaEnded(object sender, RoutedEventArgs e)
        {
            Stop();
        }

        //----------------------------------------------------------------------------
        // MediaElement 関連処理
        //----------------------------------------------------------------------------

        /// <summary>
        /// 再生
        /// </summary>
        private void Play()
        {
            mediaElement.Play();
            m_stateCurrent = MediaState.Play;
        }

        /// <summary>
        /// 一時停止
        /// </summary>
        private void Pause()
        {
            mediaElement.Pause();
            m_stateCurrent = MediaState.Pause;
        }

        /// <summary>
        /// 停止
        /// </summary>
        private void Stop()
        {
            mediaElement.Stop();
            m_stateCurrent = MediaState.Stop;
            slider.Value = 0;
        }

        /// <summary>
        /// スライダー値とMediaElement再生位置を同期する
        /// </summary>
        private void SyncSliderAndSeek()
        {
            if (m_stateCurrent == MediaState.Play || m_stateCurrent == MediaState.Pause)
            {
                if (m_dbLastSliderValue == slider.Value)
                {
                    // 動画経過時間に合わせてスライダーを動かす
                    double dbPrg = GetMovieProgress();
                    slider.Value = dbPrg * slider.Maximum;
                    m_dbLastSliderValue = slider.Value;

                    if (GetMediaState(mediaElement) == MediaState.Pause && m_stateCurrent == MediaState.Play)
                    {
                        mediaElement.Play();
                    }
                }
                else
                {
                    // Sliderを操作したとき
                    if (m_stateCurrent == MediaState.Play)
                    {
                        mediaElement.Pause();
                    }

                    // スライダーを動かした位置に合わせて動画の再生箇所を更新する
                    double dbSliderValue = slider.Value;
                    double dbDurationMS = mediaElement.NaturalDuration.TimeSpan.TotalMilliseconds;

                    int nSetMS = (int)(dbSliderValue * dbDurationMS / slider.Maximum);
                    mediaElement.Position = TimeSpan.FromMilliseconds(nSetMS);
                    m_dbLastSliderValue = slider.Value;
                }
            }
        }

        /// <summary>
        /// MediaElement 再生位置取得
        /// </summary>
        /// <returns></returns>
        private double GetMovieProgress()
        {
            TimeSpan tsCrnt = mediaElement.Position;
            TimeSpan tsDuration = mediaElement.NaturalDuration.TimeSpan;
            double dbPrg = tsCrnt.TotalMilliseconds / tsDuration.TotalMilliseconds;
            return dbPrg;
        }

        /// <summary>
        /// MediaElementステータス取得
        /// </summary>
        /// <param name="mediaElement"></param>
        /// <returns></returns>
        private MediaState GetMediaState(MediaElement mediaElement)
        {
            FieldInfo hlp = typeof(MediaElement).GetField("_helper", BindingFlags.NonPublic | BindingFlags.Instance);
            object helperObject = hlp.GetValue(mediaElement);
            FieldInfo stateField = helperObject.GetType().GetField("_currentState", BindingFlags.NonPublic | BindingFlags.Instance);
            MediaState state = (MediaState)stateField.GetValue(helperObject);
            return state;
        }
    }
}


参考:

MediaElement クラス (System.Windows.Controls)
オーディオとビデオのいずれかまたはその両方を含むコントロールを表します。
方法: MediaElement (再生、一時停止、停止、ボリューム、および速度) を制御する - WPF .NET Framework
Windows Presentation Foundation (WPF) でメディアの再生を制御します。 開始、停止、一時停止、前後へのスキップ、ボリュームと速度の調整を行います。

コメント

タイトルとURLをコピーしました