播放器在加载一个新视频的时候,通常会把当前画面清空,然后开始渲染新视频内容,但是播放器在加载到渲染的过程中需要一定的时间,虽然时间不长,但是在视频切换的过程中用户还是能看到屏幕会出现黑屏的情况。所以理想的解决办法是,播放器在加载过程中不清空画面,依旧保留上一个视频的最后一帧。但是这种方案需要对播放器进行底层改造,这个对于不熟悉音视频开发的人来说是一个很大的挑战,所以本文基于WPF的MediaElement实现视频的无缝切换,本方案不需要对播放器底层进行任何改动,不过会造成CPU和资源占用的提升。
本方案的核心思路就是在播放视频后就立刻创建一个新的MediaElement对象,并且设置好下一个视频资源,等到当前视频播放完成的时候,先让新的MediaElement对象先进行Play加载资源,加载完成的时候再把这个MediaElement对象添加到界面上去,添加完成以后,移除之前的MediaElement,并且释放相关资源,同时重复开头的步骤。代码如下:
public partial class MainWindow : Window
{
string dir = @"C:\Users\w9433\Desktop\";
string[] videos = {"1.mp4","12.mp4","13.mp4"};
int index;
MediaElement mNowMediaElement;
MediaElement mNextMediaElement;
public MainWindow()
{
InitializeComponent();
Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
mNowMediaElement = new MediaElement();
mNowMediaElement.MediaEnded += Player_MediaEnded;
mNowMediaElement.MediaOpened += Player_MediaOpened;
mNowMediaElement.LoadedBehavior = MediaState.Manual;
mNowMediaElement.UnloadedBehavior = MediaState.Manual;
mNowMediaElement.Stretch = Stretch.Uniform;
string path = dir + videos[index % videos.Length];
mNowMediaElement.Source = new Uri(path, UriKind.Absolute);
ContentView.Children.Add(mNowMediaElement);//这里的ContentView就是一个根布局 我这里在xaml用的Canvas
mNextMediaElement = ReadyVideo();
mNowMediaElement.Play();
}
private void Player_MediaOpened(object sender, EventArgs e)
{
if (sender == mNextMediaElement) {
ContentView.Children.Add(mNextMediaElement);
}
}
private void Player_MediaEnded(object sender, EventArgs e)
{
mNextMediaElement.Play();
}
private MediaElement ReadyVideo()
{
MediaElement mNextMediaElement = new MediaElement();
mNextMediaElement.MediaEnded += Player_MediaEnded;
mNextMediaElement.MediaOpened += Player_MediaOpened;
mNextMediaElement.LoadedBehavior = MediaState.Manual;
mNextMediaElement.UnloadedBehavior = MediaState.Manual;
mNextMediaElement.Stretch = Stretch.Uniform;
mNextMediaElement.Loaded += MNextMediaElement_Loaded;
index++;
string path = dir + videos[index % videos.Length];
Console.WriteLine("下一个播放的视频为:" + path);
mNextMediaElement.Source = new Uri(path, UriKind.Absolute);
return mNextMediaElement;
}
private void MNextMediaElement_Loaded(object sender, RoutedEventArgs e)
{
mNowMediaElement.Stop();
mNowMediaElement.Close();
ContentView.Children.Remove(mNowMediaElement);
mNowMediaElement = mNextMediaElement;
mNextMediaElement = ReadyVideo();
}
}