WPF中两种不同的视频流的使用

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则需要相应的后置代码的配合,使用起来不如前者方便,由于其在效率方面略高,所以我们可以在效率和方便性两个方面权衡使用这两种方式。

效果如下:

点击下载源码: part1,part2. 不含视频文件的源码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值