Question

I am using Image and MediaElement in wpf project, where I show Images and Videos from file system. I have few timers, which load files to Image/MediaElement controls. Everything works for 4-5 hours, but then MediaElement Video file freezes and MediaEnded event does not occur. I restart the application, it runs without any problem, but after some hours this problem occurs again.

My WPF XAML code:

<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>

C# code:

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;
    }
Was it helpful?

Solution

I googled it and found that this was WPF graphic issue related to software rendering. The issue is solved by adding this piece of code into the ViewPageLoaded method.

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

It helped me to solve the problem. Hope it will help you too.

Got the answer from here. Thanks to @detale for the solution

OTHER TIPS

This is a complicated problem.. I'll try to explain it in depth. (and yes I have a solution for you)

lets start with What MediaElement should be capable of doing? no.. really!

Its a wildcard right? meaning that what ever you throw on it - needs to be played: Videos, Pictures, Animated Gifs, Music.. Ok..
Now.. Each of those categories has multiple Formats (or standards).. Gif,Png.. Wmv,Mp4...
And so, each of those files we use was created by some other editor
(which has a player that can play it implemented inside - that's for sure..)

It seems that most of the companies cut expenses - they don't always (usually that is..) implement a standard in full.. so what we get as result files are not always 1:1 to the standard.

So what is perfect file format for one player can be considered as too corrupted for another player.

And while the commercial/advanced players are designed to be tolerant to corruptions and "flavors" of a file written in some standard - MediaElement - well.. is more simplistic and perhaps it is too simplistic compared to what you may throw at it to play.

So when it stump into that type of problem - yes.. it may freeze and will not report - and that is something that I can blame Microsoft in full - and why? because it is an acceptable defect to freeze but it is not acceptable (and extremely irresponsible!) to ignore it and not notify the program which using the MediaElement that it frozen or encountered a serious presentation error..
But as I said, this is Microsoft problem and definitely not your fault.

So what are the solutions?

You may try to say to yourself "Fine - I'll just get another component to play videos or use a 3rd party plug-in..", But no my friend, Doing that will not really solve your problem as you do not know if what you about to put in replace would not suffer from the exact same problem..

So the only option you are left with is to create your own "custom" standard - relax, I do not mean you need to develop a new standard - I just mean you need to create a standard tactic to make sure that what you going to throw on the MediaElement will be played with no freezes..

So, If your app going to play videos which are being used as resources - You may want to use in example the latest version of AnyVideoConverter to convert all your videos to mp4. For me it worked rather well, videos which were freezing in wmv converted to mp4 and are now tolerated by the MediaElement very smoothly. it is not the MP4 that did the trick but the conversion itself - I believe that ANV creates a "modernized" video file of any of the standards you may use for your files.

However, If your videos are dynamic/uploaded to your app during runtime or something like that - you will have to make sure to pass any video your app about to run through what you choose as "standardizer" before you can actually throw them at the MediaElement.

By the way, Browsers suffer from the same problem occasionally.

I just hope all this may sort the problem for anyone else who encountered it.

You are creating lots of BitmapImage instances, there is memory leak in BitmapImage class, The BitmapImage keeps a reference to the source stream (presumably so that you can read the StreamSource property at any time), so it keeps the MemoryStream object alive. This is causing Memory out exception. Read this, he has created a nice wrapper for stream, It worked for me.

He created an Instance of stream in wrapperclass which get disposed when you call dispose method of wrapper and BitmapImage.Source only has empty wrapper class which doesn't have any reference to original stream.

I would suggest registering for the MediaElement.MediaFailed event. See if it returns anything to you.

However, as others have mentioned this sounds like a memory issue. You can use the WPF Performance Suite or even just the task manager to confirm this. Watch for a very gradual increase in memory usage.

As Shivam cv has mentioned, it could be the BitmapImage is the leak. Try commenting it out of your solution and see if that fixes the issue.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top