WPF的MediaElement视频冻结

0bj*_*3ct 6 c# windows wpf mediaelement

我正在使用WPF项目形象和MediaElement的,我在那里展示的图片和视频从文件系统.我有几个定时器,加载文件到图像/ MediaElement的控制.一切工作4-5小时,但随后的MediaElement视频文件,冻结和MediaEnded事件不会发生.我重新启动应用程序,它运行没有任何问题,但几个小时后,这个问题再次出现.

我的WPF XAML代码:

<Grid Name="MainGrid">
    <Image HorizontalAlignment="Center" VerticalAlignment="Center" Name="MainImage" Stretch="Fill" />
    <MediaElement MediaEnded="MediaEnded" MediaOpened="MediaOpened" LoadedBehavior="Manual" HorizontalAlignment="Center" Name="VideoControl" VerticalAlignment="Center"  
                   Stretch="Fill" UnloadedBehavior="Manual"/>
</Grid>
Run Code Online (Sandbox Code Playgroud)

C#代码:

public partial class ImageView
{
    private static readonly Logger Log = LogManager.GetCurrentClassLogger();
    private static String _advCheckGuid;
    private List<String> _FolderNames;
    private int _FolderIndex = 0;
    private MainWindow _MainWindow;
    private List<String> _PathList;
    private List<String> _CheckPathList; 
    private int _Index;
    private BitmapImage _BitmapImage;
    private volatile bool _Running = true;
    private Backend _Backend;
    private ApplicationDeployment _UpdateCheck;

    // Threads
    private Timer _ImageTimer;
    private Timer _UpdateTimer;
    private Timer _FolderClearTimer;
    private Timer _CheckApplicationUpdateTimer;
    private Thread _TerminationThread;


    public ImageView()
    {
        InitializeComponent();
        _PathList = new List<string>();
        _CheckPathList = new List<string>();
        _Index = 0;

    }

    private void ViewPageLoaded(Object sender, EventArgs e)
    {

        _FolderNames = new List<string> { Constants.AdsFolderFirst, 
                                          Constants.AdsFolderSecond };

        _Backend = new Backend();



        _MainWindow = (MainWindow)Window.GetWindow(this);


        _ImageTimer = new Timer(Constants.DefaultImageTimer);
        _ImageTimer.Elapsed += ChangeImageSource;
        _ImageTimer.Start();


    }


    private void ChangeImageSource(object sender, System.Timers.ElapsedEventArgs e)
    {
        Application.Current.Dispatcher.Invoke(
            DispatcherPriority.Normal, new Action(
                  delegate()
                  {
                      try
                      {
                          if (MainImage != null && MainImage.Source != null)
                          {
                              MainImage.Source = null;
                          }

                          if (VideoControl != null && VideoControl.Source != null)
                          {
                              VideoControl.Stop();
                              VideoControl.Source = null;
                          }

                          if (_Index >= _PathList.Count)
                          {
                              _Index = 0;
                          }

                          if (_PathList.ElementAt(_Index) != null)
                          {

                              Log.Info(String.Format("Start [ChangeImageSource]. Element: {0}, Index: {1}", _PathList.ElementAt(_Index), _Index));

                              try
                              {
                                  _ImageTimer.Stop();

                                  String[] checkExt = _PathList.ElementAt(_Index).Split('.');
                                  String ext = checkExt[checkExt.Length - 1];

                                  if (ext.Equals("jpg", StringComparison.CurrentCultureIgnoreCase) ||
                                      ext.Equals("jpeg", StringComparison.CurrentCultureIgnoreCase) ||
                                      ext.Equals("png", StringComparison.CurrentCultureIgnoreCase))
                                  {
                                      _ImageTimer.Interval = Constants.NormalImageTimer;
                                      ShowImage(_PathList.ElementAt(_Index));
                                  }

                                  else if (ext.Equals("mp4", StringComparison.CurrentCultureIgnoreCase) ||
                                           ext.Equals("3gp", StringComparison.CurrentCultureIgnoreCase))
                                  {
                                      _ImageTimer.Interval = Constants.VideoDefaultTimer;
                                      PlayQueue(_PathList.ElementAt(_Index));
                                  }

                                  _ImageTimer.Start();
                                  _Index++;
                              }
                              catch (Exception exception)
                              {
                                  Log.ErrorException(exception.Message, exception);
                              }
                          }
                      }
                      catch (Exception exception)
                      {
                          Log.ErrorException(exception.Message, exception);
                      }
                  }));
    }


    private void ShowImage(String fileName)
    {
        try
        {
            if (!String.IsNullOrEmpty(fileName))
            {

                _BitmapImage = LoadImage(fileName);
                MainImage.Source = _BitmapImage;

            }
        }
        catch (Exception e)
        {
            Log.ErrorException(e.Message, e);
        }
    }


    private void PlayQueue(String fileName)
    {

        try
        {
            if (!String.IsNullOrEmpty(fileName))
            {
                VideoControl.LoadedBehavior = MediaState.Play;
                VideoControl.Source = new Uri(fileName, UriKind.Absolute);
            }
        }
        catch (Exception e)
        {
            Log.ErrorException(e.Message, e);
        }

    }



    private void MediaEnded(object sender, EventArgs e)
    {
        try
        {
            if (MainImage != null && MainImage.Source != null)
            {
                MainImage.Source = null;
            }

            if (VideoControl != null && VideoControl.Source != null)
            {
                VideoControl.Stop();
                VideoControl.Source = null;
            }

            if (_Index >= _PathList.Count)
            {
                _Index = 0;
            }

            if (_PathList.ElementAt(_Index) != null)
            {

                Log.Info(String.Format("Start [MediaEnded oper]. Element: {0}, Index: {1}", _PathList.ElementAt(_Index), _Index));

                try
                {
                    _ImageTimer.Stop();

                    String[] checkExt = _PathList.ElementAt(_Index).Split('.');
                    String ext = checkExt[checkExt.Length - 1];

                    if (ext.Equals("jpg", StringComparison.CurrentCultureIgnoreCase) ||
                        ext.Equals("jpeg", StringComparison.CurrentCultureIgnoreCase) ||
                        ext.Equals("png", StringComparison.CurrentCultureIgnoreCase))
                    {
                        _ImageTimer.Interval = Constants.NormalImageTimer;
                        ShowImage(_PathList.ElementAt(_Index));
                    }

                    else if (ext.Equals("mp4", StringComparison.CurrentCultureIgnoreCase) ||
                             ext.Equals("3gp", StringComparison.CurrentCultureIgnoreCase))
                    {
                        _ImageTimer.Interval = Constants.VideoDefaultTimer;
                        PlayQueue(_PathList.ElementAt(_Index));
                    }

                    _ImageTimer.Start();
                    _Index++;
                }
                catch (Exception exception)
                {
                    Log.ErrorException(exception.Message, exception);
                }
            }
        }
        catch (Exception exception)
        {
            Log.ErrorException(exception.Message, exception);
        }

    }



    private void MediaOpened(object sender, EventArgs e)
    {

    }



    private BitmapImage LoadImage(string myImageFile)
    {
        BitmapImage myRetVal = null;

        if (!String.IsNullOrEmpty(myImageFile))
        {
            var image = new BitmapImage();
            try
            {
                using (FileStream stream = File.OpenRead(myImageFile))
                {
                    image.BeginInit();
                    image.CacheOption = BitmapCacheOption.OnLoad;
                    image.StreamSource = stream;
                    image.EndInit();
                }
            }
            catch (Exception exception)
            {
                Log.ErrorException(exception.Message, exception);
            }

            myRetVal = image;
        }

        return myRetVal;
    }
Run Code Online (Sandbox Code Playgroud)

0bj*_*3ct 5

我用谷歌搜索,发现这是与软件渲染相关的 WPF 图形问题。通过将这段代码添加到ViewPageLoaded方法中可以解决该问题。

        try
        {
            var hwndSource = PresentationSource.FromVisual(this) as HwndSource;
            var hwndTarget = hwndSource.CompositionTarget;
            hwndTarget.RenderMode = RenderMode.SoftwareOnly;
        }
        catch (Exception ex)
        {
            Log.ErrorException(ex.Message, ex);
        }
Run Code Online (Sandbox Code Playgroud)

它帮助我解决了这个问题。希望它也能帮助你。

这里得到了答案。感谢@detale 提供的解决方案


G.Y*_*G.Y 5

这是一个复杂的问题..我会尝试深入解释它。(是的,我有一个解决方案)

让我们从MediaElement 应该能够做什么开始?不完全是!

它是一个通配符,对吗?这意味着无论你扔什么 - 都需要播放:视频,图片,动画
Gif,音乐......好吧......现在......每个类别都有多种格式(或标准)...... Gif,Png .. Wmv, Mp4...
因此,我们使用的每个文件都是由其他编辑器创建的
(其中有一个可以播放的播放器在内部实现-这是肯定的...)

似乎大多数公司都削减了开支-他们没有t 总是(通常是..)完全实现一个标准..所以我们得到的结果文件并不总是与标准1:1。

那么对于一个播放器来说什么是完美的文件格式对于另一个播放器来说可以被认为是太损坏了。

虽然商业/高级播放器被设计为可以容忍以某种标准编写的文件的损坏和“风味” - MediaElement - 好吧.. 更简单,也许与您可能投入的玩游戏相比,它过于简单.

所以当它遇到那种类型的问题时——是的......它可能会冻结并且不会报告——我可以完全责怪微软——为什么?因为冻结是一个可以接受的缺陷,但忽略它并且不通知使用 MediaElement 的程序它冻结或遇到严重的演示错误是不可接受的(并且非常不负责任!)
但正如我所说,这是微软问题,绝对不是你的错。

那么有哪些解决方法呢?

您可能会尝试对自己说“好吧 - 我只会得到另一个组件来播放视频或使用 3rd 方插件..”,但是我的朋友没有,这样做并不能真正解决您的问题,因为您不知道如果您要替换的内容不会遇到完全相同的问题..

所以你剩下的唯一选择就是创建你自己的“自定义”标准——放松,我不是说你需要开发一个新标准——我只是说你需要创建一个标准策略来确保你要做什么投掷 MediaElement 将在不冻结的情况下播放..

因此,如果您的应用程序要播放用作资源的视频 - 您可能希望在示例中使用最新版本的 AnyVideoConverter 将所有视频转换为 mp4。对我来说,它工作得相当好,在 wmv 中冻结的视频转换为 mp4,现在 MediaElement 可以非常顺利地容忍。不是 MP4 起到了作用,而是转换本身——我相信 ANV 创建了一个“现代化”的视频文件,它包含您可能用于文件的任何标准。

但是,如果您的视频在运行时或类似情况下是动态的/上传到您的应用程序 - 您必须确保通过您的应用程序将运行的任何视频通过您选择的“标准化器”,然后才能真正将它们扔到媒体元素。

顺便说一下,浏览器偶尔会遇到同样的问题。

我只是希望所有这些都可以为遇到它的其他人解决问题。