2014-01-07 53 views
0

我正在製作一個視頻項目。在那個項目中會有一個視頻在播放給用戶,如果用戶點擊了一個按鈕 - 那個視頻就會變成下一個。要點是,下一個視頻將從上一個停止點播放(所以如果用戶在00:00:30按下NEXT按鈕,下一個視頻將從該點播放)。切換媒體元素視頻

我現在面臨的問題是,總是有黑屏,直到下一個視頻將發揮的片刻,我想改變要平整,而用戶觀看了一兩秒鐘黑屏。

到目前爲止,我已經試過一個MediaElement的,並有兩個mediaElements來解決這個問題:

mediaElement變化代碼:

TimeSpan Time = mediaElement1.Position; 
mediaElement1.Source = new Uri("NEXT VIDEO LOCATION"); 
mediaElement1.Position = Time; 
mediaElement1.Play(); 

兩個mediaElement S碼:

TimeSpan Time = mediaElement1.Position; 
mediaElement2.Source = new Uri("NEXT VIDEO LOCATION"); 
mediaElement2.Position = Time; 
mediaElement1.Visibility = Visibility.Hidden; 
mediaElement1.Source = null; 
mediaElement2.Visibility = Visibility.Visible; 
mediaElement2.Play(); 

在兩次嘗試中,視頻之間沒有平滑切換。預先感謝有關此事的任何信息。

回答

2

對不起,如果我不像我一樣清楚。實際上,MediaElement具有Position屬性,但它不是DependancyProperty,並且不是可綁定的。也無法直接通過事件檢索更新的位置。所以我很久以前使用的方式是在StoryBoard中使用MediaTimeLine。你應該看看這個帖子,來自Microsoft的How to: Control a MediaElement by Using a Storyboard。 我用這種方式使用MediaElement來查找視頻文件。另一種方式是使用名爲WPFMediaKit的第三方庫,這非常有用。你可以找到它 WPF MediaKit - For webcam, DVD and custom video support in WPF

第一實例:使用WPFMediaKit(沒有實際的方式來播放MP4文件...)

在WPF MediaKit的MediaUriElement允許你綁定其MediaPosition,因爲它是一個DependancyProperty 。該MediaUriElement是圍繞淨MediaElement一個包裝物,在functionnalities差。所以,參考我的第一個答案,我寫了一個非常簡單的POCO。你可以寫這樣的事情:

MainWindow.xaml

<Window x:Class="Media.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:media="clr-namespace:WPFMediaKit.DirectShow.Controls;assembly=WPFMediaKit" 
    Title="MainWindow" Height="350" Width="525"> 
<Window.Resources> 
    <Storyboard x:Key="SwitchToSecondPlayerStoryboard"> 
     <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="firstPlayer"> 
      <DiscreteObjectKeyFrame KeyTime="0:0:0.7" Value="{x:Static Visibility.Collapsed}"/> 
     </ObjectAnimationUsingKeyFrames> 
     <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="secondPlayer"> 
      <DiscreteObjectKeyFrame KeyTime="0:0:0.7" Value="{x:Static Visibility.Visible}"/> 
     </ObjectAnimationUsingKeyFrames> 
    </Storyboard> 
</Window.Resources> 
<Window.Triggers> 
    <EventTrigger RoutedEvent="ButtonBase.Click" SourceName="switchButton"> 
     <BeginStoryboard Storyboard="{StaticResource SwitchToSecondPlayerStoryboard}"/> 
    </EventTrigger> 
</Window.Triggers> 
<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition/> 
     <RowDefinition Height="60"/> 
    </Grid.RowDefinitions> 
    <media:MediaUriElement x:Name="firstPlayer" Source="firstFile.wmv" LoadedBehavior="Play"/> 
    <media:MediaUriElement x:Name="secondPlayer" Source="secondFile.wmv" MediaPosition="{Binding Path=MediaPosition, ElementName=firstPlayer}" Visibility="Collapsed" Volume="0"/> 

    <Button Grid.Row="1" x:Name="switchButton" Content="SWITCH NEXT FILE" HorizontalAlignment="Center" VerticalAlignment="Center" Click="OnSwitchButtonClick"/> 
</Grid> 

這裏是MainWindow.xaml。cs

namespace Media 
{ 
    /// <summary> 
    /// Logique d'interaction pour MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
     } 

     private void OnSwitchButtonClick(object sender, RoutedEventArgs e) 
     { 
      //Do whatever you want with the players. 
     } 
    } 
} 

此程序的工作原理並沒有「空白屏幕」效果。您只需改進Storyboard轉換(帶有FadeIn效果的示例),但這是原則。 你也會注意到第二個的MediaPosition綁定到第一個的MediaPosition。 這意味着總是檢查MediaPosition是否低於該文件的Duration以避免錯誤,但這只是代碼的東西。

請注意,我簡化了我的代碼,避免使用MVVM和其他體系結構,以保持更清晰。

第二溶液:使用MediaElement

MainWindow.xaml解決方法

<Window x:Class="Media.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
    <Window.Resources> 
     <Storyboard x:Key="ShowSecond"> 
      <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="firstMediaElement"> 
       <DiscreteObjectKeyFrame KeyTime="0:0:0.3" Value="{x:Static Visibility.Collapsed}"/> 
      </ObjectAnimationUsingKeyFrames> 
      <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="secondMediaElement"> 
       <DiscreteObjectKeyFrame KeyTime="0:0:0.3" Value="{x:Static Visibility.Visible}"/> 
      </ObjectAnimationUsingKeyFrames> 
     </Storyboard> 
    </Window.Resources> 
    <Window.Triggers> 
     <EventTrigger RoutedEvent="ButtonBase.Click" SourceName="btnlaunchNext"> 
      <BeginStoryboard Storyboard="{StaticResource ShowSecond}"/> 
     </EventTrigger> 
    </Window.Triggers> 
    <Grid> 
     <StackPanel Background="Black"> 

      <MediaElement Name="firstMediaElement" LoadedBehavior="Manual" Source="firstFile.mp4" Width="260" Height="150" Stretch="Fill" /> 
      <MediaElement Name="secondMediaElement" Volume="0" LoadedBehavior="Manual" Source="secondFile.mp4" Visibility="Collapsed" Width="260" Height="150" Stretch="Fill" /> 

      <!-- Buttons to launch videos. --> 
      <Button x:Name="btnlaunch" Content="PLAY FIRST" Click="OnLaunchFirstButtonClick"/> 
      <Button x:Name="btnlaunchNext" Content="PLAY NEXT" Click="OnLaunchNextButtonClick"/> 

     </StackPanel> 
    </Grid> 
</Window> 

MainWindow.xaml.cs

using System; 
using System.Timers; 
using System.Windows; 

namespace Media 
{ 
    /// <summary> 
    /// Interaction logic for pour MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     public TimeSpan Position { get; set; } 

     Timer _updateTimer; 

     public MainWindow() 
     { 
      InitializeComponent(); 

      //Timer interval fixed to 1 second to read the actual position of the first media element 
      this._updateTimer = new Timer(1000); 
      this._updateTimer.Elapsed += this.UpdateTimerElapsed; 
     } 

     //The callback of your update timer 
     private void UpdateTimerElapsed(object sender, ElapsedEventArgs e) 
     { 
      //I use the dispatcher because you call the Position from another thread so it has to be synchronized 
      Dispatcher.Invoke(new Action(() => this.Position = firstMediaElement.Position)); 
     } 

     //When stopping the first, you start the second and set its Position 
     private void OnLaunchNextButtonClick(object sender, RoutedEventArgs e) 
     { 
      this.firstMediaElement.Stop(); 

      this.secondMediaElement.Volume = 10; 
      this.secondMediaElement.Play(); 
      this.secondMediaElement.Position = this.Position; 
     } 

     //When you start the first, you have to start the update timer 
     private void OnLaunchFirstButtonClick(object sender, RoutedEventArgs e) 
     { 
      this.firstMediaElement.Play(); 
      this._updateTimer.Start(); 
     } 
    } 
} 

這些都是隻能提供簡單的解決方案。有不同的方法來做到這一點,特別是使用MediaTimeline,但實現並不像看起來那麼容易,關於你面臨的問題。第二個例子,第一個例子是完全編譯和運行,並且以我想要的目標爲目標。

希望這會有所幫助。隨時給我您的反饋。

+0

謝謝你的所有詳細解答。可悲的是,我不太瞭解StoryBoard和MediaKit如何幫助我實現我的要求。 –

+0

我剛剛編輯我的帖子來編寫一個WPFMediaKit的使用示例。它像你想要的那樣工作。讓我知情。 – jhontarrede

+0

我真的很抱歉,我很困擾你,但我無法讓MediaUriElement工作。我做了一個新的項目,我添加了對WPFMediaKit.dll的引用,並且還做了xmlns:media。我的程序只包含這一行:。沒有編譯錯誤,但是當我運行它時,它只是不起任何作用。我錯過了什麼嗎?從來沒有與DLL的工作之前..非常感謝。 –

0

有沒有辦法預載下一個視頻?如果是這種情況,可以嘗試在每個MediaElement上加載兩個源,然後在播放時將第一個和第二個的Position綁定。 第二MediaElementCollapsed默認和將成爲visible及其Source已裝入,並且其Position已綁定在第一MediaElement位置(從Hidden優選使用當重圖形元素關於性能)。

希望這會有所幫助。

+0

我知道下一個視頻是什麼,所以我可以預先加載它。我遇到了你提到的綁定位置的問題,請幫助我解決這個問題?非常感謝 ! –

+0

我的新答案有幫助嗎?如果您需要,隨時可以多問一些。 – jhontarrede