WPF中的进行视频的播放有两种方式:一种是采用MediaElement+VisualBrush的方式;而另一种则是采用MediaPlayer+VideoDrawing的方式。考虑到MediaElement在处理视频时会将布局的Stretch和StretchDirect缩放视频窗口的内容以适应包容器,而MediaPlayer相反则不需要管理布局、焦点以及所有其他元素细节。所以后者相比前者有更高的效率。当然现代的处理器下是不会看到这两者的明显的区别的。不过笔者试了一下,在.Net Framework 3.5下对同一视频的两个窗口,会出现其中一个窗口的视频帧率不一样的情况,也就是说一个窗口的视频播放很平滑的,而另一个则以动画的形式出现,这可能是在3.5下为了实现同步,不得不使用剪帧技术造成的。不过我试着将同一个项目升级到.net Framework 4.0下,则不会出现此类现象,可见微软在4.0下做了不小的优化技术。正如微软在发布4.0所说的一样,其效率已经大大的改进了,一点儿不假。
当然我个人建议在使用视频播放设计中,应该使用4.0框架,这样可以很高效地运行你开发的视频播放程序。这是闲话,现在言归正传,我在这个例子中使用了两种不同的方式来实现视频播放的控制,实现一些比较通行的视频编程框架。
同样我们还是先来了解一下几个比较重要的类型:
MediaTimeline 类
一个 Timeline 对象,它控制媒体计时的方式,与动画时间线对象控制动画的方式相同。这个类型有一个很重要的方法CreateClock();它的签名如下:
public MediaClock CreateClock();创建一个与 MediaTimeline 关联的新的 MediaClock。
MediaClock 类
通过 MediaTimeline 维护媒体的计时状态的类。 通过它我们可以同步MediaElement和MediaPlayer对象。以实现视频播放的控制。
public ClockController Controller { get; }这个属性是对播放进行控制。
VisualBrush 类
使用 Visual 绘制区域。
public Visual Visual { get; set; }设置源对象。
public Transform RelativeTransform { get; set; }获取或设置要使用相对坐标应用于画笔的变换。
DrawingBrush 类
用 Drawing 绘制区域,其中可以包括形状、文本、视频、图像或其他绘图。
方式一:MediaElement+VisualBrush
步骤1:布置可视元素:这里为了实现的方便,我们在主窗体中放置了一个两行的Grid控件,第一行胜于按键控件的安装,第二行用于视频的播放和倒影窗口,相应的代码如下:
代码
<
Window.Resources
>
<
MediaElement x:Key
=
"
video
"
Source
=
"
future_nasa.wmv
"
Stretch
=
"
Fill
"
LoadedBehavior
=
"
Manual
"
/>
Window.Resources
>
<
Grid x:Name
=
"
LayoutRoot
"
Background
=
"
#FFC7DAE5
"
>
<
Grid.RowDefinitions
>
<
RowDefinition Height
=
"
50
"
/>
<
RowDefinition Height
=
"
1*
"
/>
<
RowDefinition Height
=
"
1*
"
/>
Grid.RowDefinitions
>
<
Border x:Name
=
"
orgin
"
BorderBrush
=
"
DarkGray
"
BorderThickness
=
"
1
"
Grid.Row
=
"
1
"
CornerRadius
=
"
2
"
>
Border
>
<
Border BorderBrush
=
"
Black
"
BorderThickness
=
"
1
"
Grid.Row
=
"
2
"
CornerRadius
=
"
2
"
Background
=
"
Black
"
>
<
Rectangle x:Name
=
"
reflector
"
VerticalAlignment
=
"
Stretch
"
Stretch
=
"
Fill
"
HorizontalAlignment
=
"
Stretch
"
>
Rectangle
>
Border
>
<
Border x:Name
=
"
controls
"
BorderThickness
=
"
3
"
CornerRadius
=
"
3
"
>
<
Border.BorderBrush
>
<
LinearGradientBrush EndPoint
=
"
0.5,1
"
StartPoint
=
"
0.5,0
"
>
<
GradientStop Color
=
"
#FF98BBD2
"
Offset
=
"
0
"
/>
<
GradientStop Color
=
"
White
"
Offset
=
"
1
"
/>
<
GradientStop Color
=
"
#FFBDD3E2
"
Offset
=
"
0.648
"
/>
<
GradientStop Color
=
"
#FFD3E1EB
"
Offset
=
"
0.258
"
/>
LinearGradientBrush
>
Border.BorderBrush
>
<
Rectangle
>
<
Rectangle.Fill
>
<
LinearGradientBrush EndPoint
=
"
0.5,1
"
StartPoint
=
"
0.5,0
"
>
<
GradientStop Color
=
"
#CCFFFFFF
"
Offset
=
"
1
"
/>
<
GradientStop Color
=
"
#33FFFFFF
"
/>
LinearGradientBrush
>
Rectangle.Fill
>
Rectangle
>
Border
>
<
StackPanel Orientation
=
"
Horizontal
"
>
<
Button x:Name
=
"
tme
"
Content
=
"
Test MediaElement
"
Width
=
"
125
"
Height
=
"
30
"
Margin
=
"
50,0,20,0
"
Click
=
"
tme_Click
"
/>
<
Button x:Name
=
"
tmp
"
Content
=
"
Test MediaPlayer
"
Width
=
"
125
"
Height
=
"
30
"
Margin
=
"
0,10
"
Click
=
"
tmp_Click
"
/>
<
Button x:Name
=
"
start
"
Content
=
"
Start
"
Width
=
"
75
"
Height
=
"
30
"
Margin
=
"
20,10,0,10
"
Click
=
"
start_Click
"
/>
<
Button x:Name
=
"
stop
"
Content
=
"
Stop
"
Width
=
"
75
"
Height
=
"
30
"
Margin
=
"
20,10,0,10
"
Click
=
"
stop_Click
"
/>
<
Button x:Name
=
"
resume
"
Content
=
"
Resume
"
Width
=
"
75
"
Height
=
"
30
"
Margin
=
"
20,10,0,10
"
Click
=
"
resume_Click
"
/>
<
Button x:Name
=
"
pause
"
Content
=
"
Pause
"
Width
=
"
75
"
Height
=
"
30
"
Margin
=
"
20,10,0,10
"
Click
=
"
pause_Click
"
/>
StackPanel
>
Grid
>
步骤2:在代码文件的最前面声明了三个对象,以引用XAML声明的元素:
//
保存引用的元素
private
FrameworkElement reflectorElement;
private
FrameworkElement originElement;
private
MediaClock clock;
步骤3:在后置代码中处理MediaElement对象,正如XAML声明式的代码中我们看到的那样,我们这儿将MediaElement对象声明成了一个资源,这样就可以以共享方式使用元素了。这儿先引用MediaElement对象,接着声明一个MediaClock对象。相应的代码如下:
代码
MediaElement mediaElement
=
Resources[
"
video
"
]
as
MediaElement;
//
得到资源
orgin.Child
=
mediaElement;
mediaElement.Clock
=
clock;
clock.Controller.Seek(
new
TimeSpan(
0
,
0
,
0
,
2
), TimeSeekOrigin.BeginTime);
//
跳过固定的时间线
步骤4:声明一个VisualBrush对象,并利用其RelativeTransform属性将视频倒置,形成倒影图像。
VisualBrush brush
=
new
VisualBrush();
brush.Visual
=
mediaElement;
//
使用MediaElement对象
brush.RelativeTransform
=
new
ScaleTransform { ScaleY
=
-
1
, CenterY
=
0.5
};
//
通过VisualBrush对象进行布局控制
步骤5:实现蒙版效果,即设置OpacityMask的透明掩码。
代码
LinearGradientBrush maskBrush
=
new
LinearGradientBrush { StartPoint
=
new
Point(
0
,
0
), EndPoint
=
new
Point(
0
,
1
) };
GradientStop stopOne
=
new
GradientStop { Color
=
Colors.Black, Offset
=
0
};
GradientStop stopTwo
=
new
GradientStop { Color
=
Colors.Transparent, Offset
=
0.875
};
maskBrush.GradientStops.Add(stopOne);
maskBrush.GradientStops.Add(stopTwo);
//
生成掩码的对象
reflector.Fill
=
brush;
reflector.OpacityMask
=
maskBrush;
至此,我们就实现了VisualElement+VisualBrush的组合实现了视频的播放。
方式二:MediaPlayer+DrawingBrush
步骤1:采用方式一的布局格式,相应代码不变。
步骤2:声明MediaPlayer对象以及时钟控制关。
代码
reflector.LayoutTransform
=
new
ScaleTransform { ScaleY
=
-
1
, CenterY
=
0.5
};
//
设置自己的布局
LinearGradientBrush maskBrush
=
new
LinearGradientBrush { StartPoint
=
new
Point(
0
,
0
), EndPoint
=
new
Point(
0
,
1
) };
GradientStop stopOne
=
new
GradientStop { Color
=
Colors.Black, Offset
=
0.875
};
GradientStop stopTwo
=
new
GradientStop { Color
=
Colors.Transparent, Offset
=
0
};
maskBrush.GradientStops.Add(stopOne);
maskBrush.GradientStops.Add(stopTwo);
reflector.OpacityMask
=
maskBrush;
//
以下是联合VideoDrawing和MediaPlayer的设置
MediaPlayer player
=
new
MediaPlayer();
//
使用MediaPlayer对象
player.Clock
=
clock;
步骤3:定义一个VideoDrawing对象,并关联到MediaPlayer对象。
代码
VideoDrawing drawing
=
new
VideoDrawing();
drawing.Rect
=
new
Rect(
150
,
0
,
100
,
100
);
drawing.Player
=
player;
//
将MediaPlayer赋给VideoDrawing
DrawingBrush brush
=
new
DrawingBrush(drawing);
//
得到使用的绘图画刷
步骤4:关联到布局元素.
代码
Rectangle border
=
new
Rectangle();
border.Stretch
=
Stretch.Fill;
orgin.Child
=
border;
border.Fill
=
brush;
orgin.Child
=
border;
reflector.Fill
=
brush;
clock.Controller.Stop();
步骤5:现在我们可以利用MediaClock对象的Controller对象来实现播放的开始、停止等控制了。
代码
private
void
start_Click(
object
sender, RoutedEventArgs e)
{
clock.Controller.Stop();
clock.Controller.Begin();
pause.IsEnabled
=
true
;
resume.IsEnabled
=
false
;
stop.IsEnabled
=
true
;
start.IsEnabled
=
false
;
}
private
void
stop_Click(
object
sender, RoutedEventArgs e)
{
clock.Controller.Stop();
start.IsEnabled
=
true
;
pause.IsEnabled
=
false
;
resume.IsEnabled
=
false
;
stop.IsEnabled
=
false
;
}
private
void
resume_Click(
object
sender, RoutedEventArgs e)
{
clock.Controller.Resume();
start.IsEnabled
=
false
;
pause.IsEnabled
=
true
;
resume.IsEnabled
=
true
;
stop.IsEnabled
=
true
;
}
private
void
pause_Click(
object
sender, RoutedEventArgs e)
{
clock.Controller.Pause();
start.IsEnabled
=
false
;
pause.IsEnabled
=
false
;
resume.IsEnabled
=
true
;
stop.IsEnabled
=
false
;
}
总结:上面的两种方式都很好地实现了视频的播放控制,通过关联到MediaTimeline时钟,我们可以控制其中的任何一种方式的实现,至于两者的效率方面,我觉得用MediaElement的方式使用更为方便,因为只需在XAML代码中简单声明即可使用,而MediaPlayer则需要相应的后置代码的配合,使用起来不如前者方便,由于其在效率方面略高,所以我们可以在效率和方便性两个方面权衡使用这两种方式。
效果如下:
![推荐:WPF中的使用视频流的两种方式_第1张图片](http://img.e-com-net.com/image/info8/942831ae12994464a81e83521e937048.jpg)
点击下载源码: part1,part2
摘自:http://www.cnblogs.com/suyan010203/archive/2010/07/12/1776053.html