WPF中兩種不同的視頻流的使用
WPF中的進(jìn)行視頻的播放有兩種方式:一種是采用MediaElement+VisualBrush的方式;而另一種則是采用MediaPlayer+VideoDrawing的方式??紤]到MediaElement在處理視頻時(shí)會(huì)將布局的Stretch和StretchDirect縮放視頻窗口的內(nèi)容以適應(yīng)包容器,而MediaPlayer相反則不需要管理布局、焦點(diǎn)以及所有其他元素細(xì)節(jié)。所以后者相比前者有更高的效率。當(dāng)然現(xiàn)代的處理器下是不會(huì)看到這兩者的明顯的區(qū)別的。不過筆者試了一下,在.Net Framework 3.5下對(duì)同一視頻的兩個(gè)窗口,會(huì)出現(xiàn)其中一個(gè)窗口的視頻幀率不一樣的情況,也就是說一個(gè)窗口的視頻播放很平滑的,而另一個(gè)則以動(dòng)畫的形式出現(xiàn),這可能是在3.5下為了實(shí)現(xiàn)同步,不得不使用剪幀技術(shù)造成的。不過我試著將同一個(gè)項(xiàng)目升級(jí)到.net Framework 4.0下,則不會(huì)出現(xiàn)此類現(xiàn)象,可見微軟在4.0下做了不小的優(yōu)化技術(shù)。正如微軟在發(fā)布4.0所說的一樣,其效率已經(jīng)大大的改進(jìn)了,一點(diǎn)兒不假。
當(dāng)然我個(gè)人建議在使用視頻播放設(shè)計(jì)中,應(yīng)該使用4.0框架,這樣可以很高效地運(yùn)行你開發(fā)的視頻播放程序。這是閑話,現(xiàn)在言歸正傳,我在這個(gè)例子中使用了兩種不同的方式來實(shí)現(xiàn)視頻播放的控制,實(shí)現(xiàn)一些比較通行的視頻編程框架。
同樣我們還是先來了解一下幾個(gè)比較重要的類型:
◆MediaTimeline 類
一個(gè) Timeline 對(duì)象,它控制媒體計(jì)時(shí)的方式,與動(dòng)畫時(shí)間線對(duì)象控制動(dòng)畫的方式相同。這個(gè)類型有一個(gè)很重要的方法CreateClock();它的簽名如下:
public MediaClock CreateClock();創(chuàng)建一個(gè)與 MediaTimeline 關(guān)聯(lián)的新的 MediaClock。
◆MediaClock 類
通過 MediaTimeline 維護(hù)媒體的計(jì)時(shí)狀態(tài)的類。 通過它我們可以同步MediaElement和MediaPlayer對(duì)象。以實(shí)現(xiàn)視頻播放的控制。
public ClockController Controller { get; }這個(gè)屬性是對(duì)播放進(jìn)行控制。
◆VisualBrush 類
使用 Visual 繪制區(qū)域。
public Visual Visual { get; set; }設(shè)置源對(duì)象。
public Transform RelativeTransform { get; set; }獲取或設(shè)置要使用相對(duì)坐標(biāo)應(yīng)用于畫筆的變換。
◆DrawingBrush 類
用 Drawing 繪制區(qū)域,其中可以包括形狀、文本、視頻、圖像或其他繪圖。
方式一:MediaElement+VisualBrush
步驟1:布置可視元素:這里為了實(shí)現(xiàn)的方便,我們?cè)谥鞔绑w中放置了一個(gè)兩行的Grid控件,第一行勝于按鍵控件的安裝,第二行用于視頻的播放和倒影窗口,相應(yīng)的代碼如下:
- <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:在代碼文件的最前面聲明了三個(gè)對(duì)象,以引用XAML聲明的元素:
- //保存引用的元素private FrameworkElement reflectorElement;
- private FrameworkElement originElement;
- private MediaClock clock;
步驟3:在后置代碼中處理MediaElement對(duì)象,正如XAML聲明式的代碼中我們看到的那樣,我們這兒將MediaElement對(duì)象聲明成了一個(gè)資源,這樣就可以以共享方式使用元素了。這兒先引用MediaElement對(duì)象,接著聲明一個(gè)MediaClock對(duì)象。相應(yīng)的代碼如下:
- MediaElement mediaElement = Resources["video"] as MediaElement;
- //得到資源orgin.Child = mediaElement;mediaElement.Clock =
- clock;clock.Controller.Seek(new TimeSpan(0, 0, 0, 2), TimeSeekOrigin.BeginTime);
- //跳過固定的時(shí)間線
步驟4:聲明一個(gè)VisualBrush對(duì)象,并利用其RelativeTransform屬性將視頻倒置,形成倒影圖像。
- VisualBrush brush = new VisualBrush();brush.Visual = mediaElement;
- //使用MediaElement對(duì)象brush.RelativeTransform = new ScaleTransform { ScaleY = -1, CenterY = 0.5 };
- //通過VisualBrush對(duì)象進(jìn)行布局控制
步驟5:實(shí)現(xiàn)蒙版效果,即設(shè)置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);//生成掩碼的對(duì)象reflector.Fill = brush;reflector.OpacityMask = maskBrush;
至此,我們就實(shí)現(xiàn)了VisualElement+VisualBrush的組合實(shí)現(xiàn)了視頻的播放。
方式二:MediaPlayer+DrawingBrush
步驟1:采用方式一的布局格式,相應(yīng)代碼不變。
步驟2:聲明MediaPlayer對(duì)象以及時(shí)鐘控制關(guān)。
- reflector.LayoutTransform = new ScaleTransform { ScaleY = -1, CenterY = 0.5 };
- //設(shè)置自己的布局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;
- //以下是聯(lián)合VideoDrawing和MediaPlayer的設(shè)置MediaPlayer player = new MediaPlayer();
- //使用MediaPlayer對(duì)象player.Clock = clock;
步驟3:定義一個(gè)VideoDrawing對(duì)象,并關(guān)聯(lián)到MediaPlayer對(duì)象。
- VideoDrawing drawing = new VideoDrawing();drawing.Rect = new Rect(150, 0, 100, 100);
- drawing.Player = player;
- //將MediaPlayer賦給VideoDrawingDrawingBrush brush = new DrawingBrush(drawing);
- //得到使用的繪圖畫刷
步驟4:關(guān)聯(lián)到布局元素.
- Rectangle border = new Rectangle();
- border.Stretch = Stretch.Fill;orgin.Child = border;
- border.Fill = brush;orgin.Child = border;
- reflector.Fill = brush;clock.Controller.Stop();
步驟5:現(xiàn)在我們可以利用MediaClock對(duì)象的Controller對(duì)象來實(shí)現(xiàn)播放的開始、停止等控制了。
- 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;}
總結(jié):上面的兩種方式都很好地實(shí)現(xiàn)了視頻的播放控制,通過關(guān)聯(lián)到MediaTimeline時(shí)鐘,我們可以控制其中的任何一種方式的實(shí)現(xiàn),至于兩者的效率方面,我覺得用MediaElement的方式使用更為方便,因?yàn)橹恍柙赬AML代碼中簡(jiǎn)單聲明即可使用,而MediaPlayer則需要相應(yīng)的后置代碼的配合,使用起來不如前者方便,由于其在效率方面略高,所以我們可以在效率和方便性兩個(gè)方面權(quán)衡使用這兩種方式。
效果如下:
原文標(biāo)題:WPF中的使用視頻流的兩種方式
鏈接:http://www.cnblogs.com/suyan010203/archive/2010/07/12/1776053.html
【編輯推薦】