WPF상에서 비디오를 재생하기 위해서 다음과 같은 2가지 객체를 이용 할 수 있습니다.
System.Window.Control.MediaElement 와 System.Window.Media.MediaFlayer가 그것입니다.
동작 영상은 http://screencast.com/t/6IoXozpFL 을 참조.
( 프레임레이트가 낮은 것은 캡처링 때문이지 WPF성능상의 문제는 아닙니다. )
MediaPlayer를 사용할 때 주의해야 할 점은 이 클래스는 직접적인 시각 표현이 없으며 시각적 트리에
직접 추가할 수 없다는 점입니다. 비디오를 재생하려면 MediaPlayer를 가져온 다음 해당 표면을
VisualBrush와 같은 시각적 트리에 추가해야 합니다.
기본적으로 MediaElement는 MediaPlayer 클래스의 상위 래퍼입니다.
소스 코드 보기..
XAML 코드
[code]
<Window x:Class="CoWorkVideoPlayer.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CoWorkVideoPlayer" Height="700" Width="640">
<Grid>
<Grid x:Name="mediaPlayerGrid" VerticalAlignment="Top" Height="300">
<Rectangle x:Name="rec" HorizontalAlignment="Stretch" Width="Auto" Fill="#FFFFEBEB" Stroke="#FF000000"/>
<StackPanel Margin="5,0,0,5" VerticalAlignment="Top" Orientation="Horizontal" HorizontalAlignment="Center">
<TextBox Text="System.Window.Media.MediaFlayer 영역입니다. " x:Name="tbmp" FontWeight="SemiBold" Height="25" FontFamily="Arial" FontSize="11" Foreground="Black" Opacity="0.6" Background="#FFFFFF" />
</StackPanel>
</Grid>
<Grid x:Name="mediaElementGrid" VerticalAlignment="Bottom">
<MediaElement x:Name="me" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto" Height="Auto"/>
<StackPanel Margin="5,0,0,5" VerticalAlignment="Top" Orientation="Horizontal" HorizontalAlignment="Center">
<TextBox Text="System.Window.Control.MediaElement 영역입니다." x:Name="tbme" FontWeight="SemiBold" Height="25" FontFamily="Arial" FontSize="11" Foreground="Black" Opacity="0.6" Background="#FFFFFF" />
</StackPanel>
<StackPanel Margin="5,0,0,5" VerticalAlignment="Bottom" Orientation="Horizontal" HorizontalAlignment="Center">
<TextBox Text="D:\download\Apple.Seed.2004.XviD.DTS.CD2-WAF.avi" x:Name="tb" FontWeight="SemiBold" Height="25" FontFamily="Arial" FontSize="11" Foreground="Black" Opacity="0.6" Background="#FFFFFF" />
<Button Margin="5,0,0,0" Width="50" Height="25" Content="LOAD" Click="OpenFIle" HorizontalAlignment="Right" />
<Button Margin="5,0,0,0" Width="50" Height="25" Content="PLAY" Click="Play" HorizontalAlignment="Right" />
<Button Margin="5,0,0,0" Width="50" Height="25" Content="STOP" Click="Stop" HorizontalAlignment="Right" />
<Button Margin="5,0,0,0" Width="50" Height="25" Content="PAUSE" Click="Pause" HorizontalAlignment="Right" />
</StackPanel>
<StackPanel Margin="5,0,0,35" VerticalAlignment="Bottom" Orientation="Horizontal" HorizontalAlignment="Center">
<Slider Cursor="Hand" x:Name="timeSlider" ValueChanged="SeekToMediaPosition"/>
</StackPanel>
</Grid>
</Grid>
</Window>
[/code]
C#코드
[code]
using System;
using System.Collections.Generic;
using System.Text;
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.Shapes;
using System.Diagnostics;
using Microsoft.Win32;
namespace CoWorkVideoPlayer
{
/// <summary>
/// 본 코드는 System.Window.Control.MediaElement 와 System.Window.Media.MediaFlayer 를
/// 동시에 WPF상에 올려 제어합니다.
/// MediaPlayer를 사용할 때 가장 주의해야 할 부분은 이 클래스는 직접적인 시각 표현이 없으며
/// 시각적 트리에 직접 추가할 수 없다는 점입니다. 비디오를 재생하려면
/// MediaPlayer를 가져온 다음 해당 표면을 VisualBrush와 같은 시각적 트리에 추가해야 합니다.
/// 기본적으로 MediaElement는 MediaPlayer 클래스의 상위 래퍼입니다
/// </summary>
public partial class Window1 : System.Windows.Window
{
//MediaElement 는 xaml영역에 설정되어 있으며
//MediaPlayer는 코드단에서 생성합니다.
MediaPlayer mp = new MediaPlayer();
Stopwatch stop = new Stopwatch();
Image videoImage = new Image();
Boolean nowPlay = false; //미디어 재생중인지여부
TimeSpan timeSpan; //Pause한 시점의 위치값 저장
public Window1()
{
//어플리케이션 윈도우 설정
this.Background = new SolidColorBrush(Color.FromArgb(0, 34, 34, 34));
this.Title = "WPF Video Player";
InitializeComponent();
tbmp.Visibility = Visibility.Hidden;
tbme.Visibility = Visibility.Hidden;
//MediaElement의 경우 LoadedBehavior,UnloadedBehavior 를
//Manual로하지않으면 미디어 제어를 할 수 없음
me.LoadedBehavior = MediaState.Manual;
me.UnloadedBehavior = MediaState.Manual;
//MediaPlayer표현영역 Rectangle 설정
rec.Stroke = new SolidColorBrush(Colors.Black);
rec.Fill = new VisualBrush(videoImage);
//Seeker 설정
timeSlider.Width = 400.0D;
timeSlider.IsEnabled = false;
timeSlider.Visibility = Visibility.Hidden;
//미디어가 오픈 이벤트 핸들러
me.MediaOpened += new RoutedEventHandler(me_MediaOpened);
tb.ToolTip = new TextBox().Text ="재생 할 미디어의 전체 경로를 입력 해 주세요";
}
/// <summary>
/// Load 버튼 클릭에 대한 이벤트로 텍스트박스의 파일을 읽어와 재생을 시작합니다.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Play(object sender, RoutedEventArgs e)
{
try
{
if (tb.Text.Length > 0)
{
me.Stop();
mp.Stop();
timeSpan = new TimeSpan(0L);
me.Source = new Uri(tb.Text);
mp.Open(new Uri(tb.Text));
me.Play();
mp.Play();
tbmp.Visibility = Visibility.Visible;
tbme.Visibility = Visibility.Visible;
nowPlay = true;
stop.Start();
//Rendering 이벤트 핸들러를 설정합니다.
VisualTarget.Rendering += renda;
}
else
{
MessageBox.Show("재생 할 미디어의 전체 경로를 택스트 상자에 입력 해 주세요");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
//미디어가 오픈되면 TimeSpan을 통해 전체 길이를 알 수 있다.
void me_MediaOpened(object sender, RoutedEventArgs e)
{
if (me.NaturalDuration.HasTimeSpan)
{
timeSlider.Maximum = me.NaturalDuration.TimeSpan.TotalMilliseconds;
System.Diagnostics.Debug.WriteLine(" timeSlider.Maximum : " + timeSlider.Maximum);
timeSlider.IsEnabled = true;
}
}
//이벤트 발생시 WPF의 Image 영역에 이미지를 뿌립니다.
private void renda(Object sender, EventArgs e)
{
try
{
RenderTargetBitmap rtb = new RenderTargetBitmap(mp.NaturalVideoWidth, mp.NaturalVideoHeight, 1 / 200, 1 / 200, PixelFormats.Pbgra32);
DrawingVisual dv = new DrawingVisual();
DrawingContext dc = dv.RenderOpen();
dc.DrawVideo(mp, new Rect(0, 0, mp.NaturalVideoWidth, mp.NaturalVideoHeight));
dc.Close();
rtb.Render(dv);
videoImage.Source = BitmapFrame.Create(rtb);
}
catch (Exception ee)
{
System.Diagnostics.Debug.WriteLine(ee.Message);
}
}
private void Stop(object sender, RoutedEventArgs e)
{
try
{
me.Stop();
mp.Stop();
timeSlider.Value = 0.0D;
timeSlider.IsEnabled = false;
tbmp.Visibility = Visibility.Hidden;
tbme.Visibility = Visibility.Hidden;
nowPlay = false;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void Pause(object sender, RoutedEventArgs e)
{
try
{
if ( nowPlay)
{
me.Pause();
mp.Pause();
timeSpan = me.Position;
nowPlay = false;
}
else
{
me.Position = timeSpan;
mp.Position = timeSpan;
me.Play();
mp.Play();
nowPlay = true;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void SeekToMediaPosition(object sender, RoutedEventArgs e)
{
int SliderValue = (int)timeSlider.Value;
// Overloaded constructor takes the arguments days, hours, minutes, seconds, miniseconds.
// Create a TimeSpan with miliseconds equal to the slider value.
TimeSpan ts = new TimeSpan(0, 0, 0, 0, SliderValue);
me.Position = ts;
mp.Position = ts;
}
private void OpenFIle(object sender, RoutedEventArgs e)
{
// 파일 열기 다이얼로그 박스를 설정
OpenFileDialog dlg = new OpenFileDialog();
dlg.DefaultExt = ".avi"; // 기본 확장자
dlg.Filter = "Video File (.avi)|*.avi|Video File (.wmv)|*.wmv|Video File (.mpg)|*.mpg|Video File (.mpeg)|*.mpeg"; // 확장 파일 필터
// Show open file dialog box
Nullable<bool> result = dlg.ShowDialog();
// Process open file dialog box results
if (result == true)
{
// Open document
//string filename = dlg.FileName;
tb.Text = dlg.FileName;
}
}
}
}
[/code]
본 코드를 작성 한 후 XP에서 테스트를 진행 했을 때 아래와 같은 현상을 발견 할 수 있었습니다.
OS |
.Net Framework |
Codec 설치여부 |
WMP 버전 |
Direct X |
영상 표시 여부 |
Win XP sp2 |
3.0 |
X |
9 |
9.0c |
X |
Win XP sp2 |
3.0 |
O |
9 |
9.0c |
X |
Win XP sp2 |
3.0 |
X |
11 |
9.0c |
X |
Win XP sp2 |
3.0 |
O |
11 |
9.0c |
O |
Win XP sp2 |
3.5 |
O |
10 |
9.0c |
O |
위 표로 미루어 보아 C#에서 제공하고 있는 MediaPlayer 클래스를 사용하기 위해서는 기본적으로
윈도우 미디어 플레이어 10이상과 플레이하고자 하는 동영상의 코덱이 필요합니다.
( 윈도우즈 Vista는 기본적으로 WMP 11 이 설치되어 있으므로 해당 코덱만 설치되어 있다면 영상이 표시됩니다.
MSDN 공식문서에도 WMP 10이상이 필요하다고 명시되어 있군요..)