背景

一款广告播放器的需求:可以循环播放多个视频当每个视频播完后立即播放下一个,中间不得有黑屏过程。 ##第一版方案 申明一个MediaElement 当每个视频播放完成后(MediaEnded)事件中指定下一个视频地址 这边就不贴出代码了 结果:每个视频交替时会有长时间空白期原因:1.设置MediaElement.source后视频缓冲需要时间(VlC就没有这问题 但是VLC在wpf下只能离屏渲染播放炒鸡卡 故放弃)。2.设置soucre后调用play()会出现不发调用成功的情况(应该正在缓冲加载,这个时候调用play()失效)。 放弃第一方案

第二方案

声明多个MediaElement每个初始化时设置source,当播放摸个视频时,显示对应的MediaElement并调用play(),否则隐藏并pause(); 结果:程序打开时开的要命,内存飙升。多个视频同时缓冲 崩溃。。。。 方案优化:

/// <summary>
    /// MainWindow3.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow3 : Window
    {
        public MainWindow3()
        {
            InitializeComponent();
        }

        public int currentindex = 0;

        public List<string> datalist = new List<string>() { AppDomain.CurrentDomain.BaseDirectory + "1.mp4", AppDomain.CurrentDomain.BaseDirectory + "2.mp4", AppDomain.CurrentDomain.BaseDirectory + "3.mp4", AppDomain.CurrentDomain.BaseDirectory + "4.mp4" };

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            MediaElement media1 = new MediaElement();
            //media1.Clock.CurrentProgress.
            media1.LoadedBehavior = MediaState.Manual;
            media1.UnloadedBehavior = MediaState.Stop;
            media1.Source = new Uri(AppDomain.CurrentDomain.BaseDirectory + "1.mp4", UriKind.Absolute);
            media1.MediaFailed += MediaFailed;
            media1.MediaEnded += MediaEnded;
            media1.Width = 400;
            media1.Height = 300;
            media1.Visibility = Visibility.Hidden;

            MediaElement media2 = new MediaElement();
            //media1.Clock.CurrentProgress.
            media2.LoadedBehavior = MediaState.Manual;
            media2.UnloadedBehavior = MediaState.Stop;
            //media2.Source = new Uri(AppDomain.CurrentDomain.BaseDirectory + "3.mp4", UriKind.Absolute);
            media2.MediaFailed += MediaFailed;
            media2.MediaEnded += MediaEnded;
            media2.Width = 400;
            media2.Height = 300;
            media2.Visibility = Visibility.Hidden;


            MediaElement media3 = new MediaElement();
            //media1.Clock.CurrentProgress.
            media3.LoadedBehavior = MediaState.Manual;
            media3.UnloadedBehavior = MediaState.Stop;
            //media2.Source = new Uri(AppDomain.CurrentDomain.BaseDirectory + "3.mp4", UriKind.Absolute);
            media3.MediaFailed += MediaFailed;
            media3.MediaEnded += MediaEnded;
            media3.Width = 400;
            media3.Height = 300;
            media3.Visibility = Visibility.Hidden;

            MediaElement media4 = new MediaElement();
            //media1.Clock.CurrentProgress.
            media4.LoadedBehavior = MediaState.Manual;
            media4.UnloadedBehavior = MediaState.Stop;
            //media2.Source = new Uri(AppDomain.CurrentDomain.BaseDirectory + "3.mp4", UriKind.Absolute);
            media4.MediaFailed += MediaFailed;
            media4.MediaEnded += MediaEnded;
            media4.Width = 400;
            media4.Height = 300;
            media4.Visibility = Visibility.Hidden;

            this.maincanvas.Children.Add(media1);
            this.maincanvas.Children.Add(media2);
            this.maincanvas.Children.Add(media3);
            this.maincanvas.Children.Add(media4);
        }


        public async void StartPlayResource()
        {
            await Task.Factory.StartNew(() =>
            {
                double endtime = 10;
                Dispatcher.Invoke(delegate
                {
                    MediaElement v = this.maincanvas.Children[currentindex] as MediaElement;
                    v.Visibility = Visibility.Visible;
                    if (v.NaturalDuration.HasTimeSpan)
                    {
                        endtime = v.NaturalDuration.TimeSpan.TotalSeconds;
                    }
                    v.Stop();
                    v.Play();
                });
                LoadNextSource(endtime);
            });
        }

        private void LoadNextSource(double seconds)
        {
            Task.Factory.StartNew(() =>
            {
                int delaytime = 10;
                if (seconds > 3)
                {
                    delaytime = (int)(seconds - 3);
                }
                else
                {
                    delaytime = 2;
                }
                Thread.Sleep(delaytime * 1000);
                Dispatcher.Invoke(delegate
                {
                    if (currentindex < datalist.Count - 1)
                    {
                        MediaElement media = this.maincanvas.Children[currentindex + 1] as MediaElement;
                        if (media.Source == null)
                        {
                            media.Source = new Uri(datalist[currentindex + 1]);
                        }
                    }
                });
            });
        }

        private void MediaFailed(object sender, ExceptionRoutedEventArgs e)
        {
            try
            {
                MessageBox.Show("报错");
            }
            catch (Exception ex)
            {

            }
        }

        private void MediaEnded(object sender, RoutedEventArgs e)
        {
            try
            {
                UIElement uiitem = sender as UIElement;
                uiitem.Visibility = Visibility.Hidden;
                if (currentindex == datalist.Count - 1)
                {
                    currentindex = 0;
                }
                else
                {
                    currentindex++;
                }
                StartPlayResource();
            }
            catch (Exception ex)
            {

            }
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                currentindex = 0;
                StartPlayResource();
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message);
            }
        }
    }

初始化的时候第一个视频赋值source 每个视频快结束是单独线程加载下一个视屏。 测试结果:播放没有问题,程序打开流畅。 其实可以在每个时候播放完成后释放资源,不然视频多了仍然会内存爆棚。 这边有一个很大的坑 在AMD独显机器上会爆硬件错误,随后只要运行视频程序(如QQ影音 迅雷影音 mediaplayer)播放视屏就会死机 至少AMD的R系列是这样。查了所有资料,仍然说不清是显卡问题还是解码器问题,但本人觉得是AMD显卡问题,而且不同版本的显卡驱动下表现得状态不一样

最后感谢德熙帮我解决AMD显卡问题,方案是使用了他们厂封装的DirectShowLib-2005的WPF控件替代了MediaElement