WPF中的使用視頻流的兩種方式

作者: suyan010203  來源: 博客園  發布時間: 2010-07-24 11:36  閱讀: 2964 次  推薦: 1   原文鏈接   [收藏]  

  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則需要相應的后置代碼的配合,使用起來不如前者方便,由于其在效率方面略高,所以我們可以在效率和方便性兩個方面權衡使用這兩種方式。

  效果如下:

  點擊下載源碼: part1part2, 不含視頻文件的源碼

1
0
 
標簽:WPF
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()