Major leaks or am I missing something?

Sep 15, 2009 at 5:46 PM

Hi, Jeremiah

I have been playing around with WpfMediaKit for a while now. As per my requirement, I have to use multiple video players (Capture or Uri) on the same window and after a some time, a seperate window takes over with different content. At this time the mediaUriElements created on previous page are destroyed(stop and close).

These two windows are repeated one after another for the lifetime of the application which could be any number of hours. I started noticing that as the time increases, the memory (commit size) and threads keep on increasing.

To test, I created a sample application with 4 videos playing using MediaUriElement and a timer running every 3 seconds, which removes the old elements from the grid, calls stop and close and adds new elements on every tick. The application soon consumes hundred of MB of RAM along with hundreds of threads and handles and after some time OutOfMemoryException comes up.

Digging deeper, I noticed that although MediaPlayer Base class has Dispose function which invokes Dispatcher.Shutdown for mediaplayerbase class but this dispose is only called when the main window is closed. So basically, all those threads stay in the memory and are never closed.

So, In all those scenarios, where the video elements are to be added and removed dynamically, WpfMediakit starts taking up the resources.

I tried adding the dispose in MediaElementBase, so I could call dispose on MediaUriElement everytime I have to remove it, but I ran into some VMR allocator problems and videos stop playing.


Is there a way to solve this? or am I missing something.

Sep 17, 2009 at 7:51 AM

Update: Demo Sample

 

Xaml:

<Window x:Class="mediaKitSample.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="600" Width="800" Loaded="Window_Loaded">
    <Grid x:Name="grdBase"  >
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        
    </Grid>
</Window>

C#:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using WPFMediaKit.DirectShow.Controls;

namespace mediaKitSample
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        DispatcherTimer timer = new DispatcherTimer(DispatcherPriority.Normal, Dispatcher.CurrentDispatcher);
        private MediaUriElement element1;
        private MediaUriElement element2;
        private MediaUriElement element3;

        public Window1()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            AddMediaUriElements();
            timer.Interval = TimeSpan.FromSeconds(3);
            timer.Tick += new EventHandler(timer_Tick);
            timer.Start();
        }

        private void AddMediaUriElements()
        {
            element1 = new MediaUriElement();
            element1.Source = new Uri(@"C:\Users\Public\Videos\Sample Videos\Bear.wmv");
         
            element2 = new MediaUriElement();
            Grid.SetColumn(element2, 1);
             element2.Source = new Uri(@"C:\Users\Public\Videos\Sample Videos\Butterfly.wmv");

            element3 = new MediaUriElement();
            Grid.SetColumnSpan(element3, 2);
            Grid.SetRow(element3, 1);
            element3.Source = new Uri(@"C:\Users\Public\Videos\Sample Videos\Lake.wmv");

            grdBase.Children.Add(element1);
            grdBase.Children.Add(element2);
            grdBase.Children.Add(element3);
        }

        void timer_Tick(object sender, EventArgs e)
        {
            timer.Stop();

            element1.Stop();
            element1.Close();
            
            element2.Stop();
            element2.Close();
         
            element3.Stop();
            element3.Close();

            grdBase.Children.Clear();

            element1 = null;
            element2 = null;
            element3 = null;

            GC.Collect(2);
            GC.WaitForPendingFinalizers();
            GC.Collect(2);
    

            AddMediaUriElements();

            timer.Start();
        }
    }
}

 

 

Sep 17, 2009 at 8:34 AM

Update: I tried to reuse the mediaUriElements. This sample code loads random files from a directory. There are 3 mediaUriElements and the videos are changed 1 at a time after every 3 seconds, but the MediaUriElements are reused for lifetime. Even in this case, after around 4-5 hours, the application starts taking up resources (Threads and memory starts increasing). Considering the scenarios where number of mediaUriElements (or capture or other elements) required are not known in advance and depend on some other dynamic factors, this type of sharing of elements across pages is quite difficult and not good. Even in this case, I am running into OutOfMemoryExceptions after a few hours. I think the best way would be to Implement IDisposable in MediaElementBase to shutdown the dispatcher and release all resources when that instance of Element is not required anymore, but when I did that I started getting other errors in VMR Allocator because the HiddenWindow is shared among all the instances of MediaElementBase which starts creating problems.

Any Suggestions??

 

XAML:

<Window x:Class="SampleApplication.TestMultipleVideosChangingReuseMediaUriElement"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="TestMultipleVideosChangingReuseMediaUriElement" Height="600" Width="800" 
    Loaded="Window_Loaded">
    <Grid x:Name="grdBase"  >
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

    </Grid>
</Window>

C#:

public partial class TestMultipleVideosChangingReuseMediaUriElement : Window
    {
        public TestMultipleVideosChangingReuseMediaUriElement()
        {
            InitializeComponent();
        }

        DispatcherTimer timer = new DispatcherTimer(DispatcherPriority.Normal, Dispatcher.CurrentDispatcher);
        private MediaUriElement _mediaUriElement1;
        private MediaUriElement _mediaUriElement2;
        private MediaUriElement _mediaUriElement3;

        private List<string> _listOfVideoFiles;
        private int _playerToStartStopNext = 0;

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            CreateMediaUriElements();
            timer.Interval = TimeSpan.FromSeconds(3);
            timer.Tick += new EventHandler(timer_Tick);
            timer.Start();
            StartMediaUriElements();
        }

        private string GetRandomFileFromDirectory()
        {
            if (_listOfVideoFiles == null)
            {
                string directory = "D:\\Videos";
                _listOfVideoFiles = new List<string>();

                string[] files1 = Directory.GetFiles(directory, "*.avi", SearchOption.AllDirectories);
                string[] files2 = Directory.GetFiles(directory, "*.wmv", SearchOption.AllDirectories);
                string[] files3 = Directory.GetFiles(directory, "*.mkv", SearchOption.AllDirectories);

                _listOfVideoFiles.AddRange(files1);
                _listOfVideoFiles.AddRange(files2);
                _listOfVideoFiles.AddRange(files3);
            }

            Random random = new Random();
            int i = random.Next(0, _listOfVideoFiles.Count - 1);
            return _listOfVideoFiles[i];
        }

        private void CreateMediaUriElements()
        {
            _mediaUriElement1 = new MediaUriElement();

            _mediaUriElement2 = new MediaUriElement();
            Grid.SetColumn(_mediaUriElement2, 1);

            _mediaUriElement3 = new MediaUriElement();
            Grid.SetColumnSpan(_mediaUriElement3, 2);
            Grid.SetRow(_mediaUriElement3, 1);
        }

        private void StartMediaUriElements()
        {
            if (_playerToStartStopNext == 0)
            {
                grdBase.Children.Add(_mediaUriElement1);
                _mediaUriElement1.Source = new Uri(GetRandomFileFromDirectory());
            }
            else if (_playerToStartStopNext == 1)
            {
                grdBase.Children.Add(_mediaUriElement2);
                _mediaUriElement2.Source = new Uri(GetRandomFileFromDirectory()); 
            }
            else if (_playerToStartStopNext == 2)
            {
                grdBase.Children.Add(_mediaUriElement3);                
                _mediaUriElement3.Source = new Uri(GetRandomFileFromDirectory());
            }
            _playerToStartStopNext++;

            if (_playerToStartStopNext > 2) _playerToStartStopNext = 0;
        }

        private void StopMediaUriElements()
        {
            if (_playerToStartStopNext == 0)
            {
                grdBase.Children.Remove(_mediaUriElement1);
                _mediaUriElement1.Stop();
            }
            else if (_playerToStartStopNext == 1)
            {
                grdBase.Children.Remove(_mediaUriElement2);
                _mediaUriElement2.Stop(); 
            }
            else if (_playerToStartStopNext == 2)
            {
                grdBase.Children.Remove(_mediaUriElement3);
                _mediaUriElement3.Stop();
            }
        }

        void timer_Tick(object sender, EventArgs e)
        {
            timer.Stop();

            StopMediaUriElements();

            GC.Collect(2);
            GC.WaitForPendingFinalizers();
            GC.Collect(2);

            StartMediaUriElements();

            timer.Start();

        }
    } 
 

Coordinator
Sep 17, 2009 at 11:27 AM
I did verify the issues you reported. 

I just made a few changes if you want to try it out.  I didn't have much time to test, but it's looking a lot better.

The VMR9 now uses one d3d device among all renders, so it should be a lot less GPU hungry (EVR code is unchanged).  I also found a few bugs that caused the Elements not to be GC'd and added a Dispose method as you suggested to the  MediaElementBase.  You will need to call the Dispose in your example.  This will call the Close internally.

Let me know how it works for you.

-Jer
Sep 17, 2009 at 2:29 PM
Edited Sep 17, 2009 at 2:32 PM

Hi, Jeremia

Thanks for the update. I have been running the sample application on the new build for 2 hours now. There is 15 MB increase in memory. Threads have increased by 5. But, handles have increased by 6500.

I will continue the testing on this and will let you know how it turns out.  I am trying to find out the source of these handle leaks, but all I can see right now are some odd 6000 int32 stuck in some hashtable/s. I will get back to you on that one.

 

<abbr></abbr>

<input id="ctl00_ctl00_MasterContent_Content_PostRepeater_ctl00_PostId" name="ctl00$ctl00$MasterContent$Content$PostRepeater$ctl00$PostId" type="hidden" value="234820" />

Hi, Jeremiah

Coordinator
Sep 17, 2009 at 8:52 PM
I think I have a fix for it.  Hope I'm not speaking too soon...

I think a major issue with the library in general is my use of the Dispatcher/Dispatcher object to use as a message pump.  It has caused weird issues in the past, where it almost seemed as if the Dispatcher would stop executing the delegate when the thread went into native code.

Anyways, it took _a lot_ of guess and checking but I think I got it, but again, not too much time to test.  Handles, memory and threads seem to level off and stay around the same numbers.

I rewrote my own implementation of a Dispatcher/Dispatcher object and removed a DispatcherTimer within MediaPlayerBase.

I'll clean up the code an commit it in a bit.
Coordinator
Sep 18, 2009 at 12:37 AM
Getting closer to the core of at least one issue.  Now that I have my own Dispatcher running the Players, I was able to quarantine some stuff.

It seems if I let the Dispatcher run the Win32 message loop, you will see leaked handles.  I currently use this to get events from the graph (ie, end of stream).  If I disable processing of the loop, the handle count doesn't leak like a sieve.

The WPF Dispatcher automatically processes the Win32 message loop, so it was uncontrollable before.

I'd like to get to the root of the issue, but worst case I can use a Win32 timer to query the graph for events (not desirable, but a work around none the less).
Sep 18, 2009 at 3:43 AM
Edited Sep 18, 2009 at 3:49 AM

I will be able to test the code only after around 4 hours. Only then I will be able to comment how this new implementation of Dispatcher works out, but I think it should be better.

Although Media Uri Player runs on a seperate dispatcher, but still they are using the same AppDomain of the application. I don't have any idea about it, but if you have an idea about the Appdomain, will it be a good thing to run each instance of media player in different appdomain, so when it is disposed, we can unload that appdomain to release all resources? If such a scenario is possible, then let me know and I will get to work on it.

Win32 timer can be a good thing in sense you will be able to add one more feature in mediaurielement (Duration of playback of the media). Just like you have position property in mediaseeking, you can set durationof playback, so media will be stopped(or looped) and  mediaended will be fired when media has actually ended or durationOfPlayback has completed whichever is earlier. Can be usefull in some scenarios. This checking can be done in that win32 timer.

Thinking about that, the position property directly sets the position of the running media once its loaded (because media player gets to know about the length of the file only when its loaded). Wouldn't it be better to modify it so that if the media is not loaded and the length is not known, the position is stored and as soon as the graph is created, the position is set.

Although we are deviating  from the issue, but its good to keep these things in mind while making changes.

Sep 18, 2009 at 11:24 AM

Since there were handle leaks in the current committed release 28150. I tried the reusing of elements.

The instances of Vmr9Allocator+<>c__DisplayClass1 (anonymous method), DispatcherOperation, DsRect, ExecutionContext
start increasing after some time.... before which they are being cleared perfectly.

 

output of !dumpheap -stat

This is the case of normal re-use of MediaUriPlayer objects, which are not disposed.. the sample no. 2, which i posted above in post #3

001384dc    30254       583544 System.Object[]
09ddef2c    29363       939616 System.Action
088c4294    29705       950560 System.Windows.Threading.PriorityItem`1[[System.Windows.Threading.DispatcherOperation, WindowsBase]]
01daa214    29724      1070064 System.Threading.ExecutionContext
0c379110    58618      1406832 WPFMediaKit.DirectShow.Interop.DsRect
05ddd600    29705      1544660 System.Windows.Threading.DispatcherOperation
0cdf2a0c    29309      1875776 WPFMediaKit.DirectShow.MediaPlayers.Vmr9Allocator+<>c__DisplayClass1


If you want complete heap dump let me know....

Coordinator
Sep 18, 2009 at 11:29 AM
The AppDomain idea is an interesting one, but I don't think it would work for fixing this scenario.  Most of the code is native via COM interop, so any native resources being used won't be unloaded with the AppDomain.  The mystery widens when you consider that all COM interfaces are managed (ref counted) by the CLR.  So a GC collect, in theory should release all unreferenced COM interfaces.  The Marshal.ReleaseCOMObject is really just done for deterministic releasing of the COM objects.

I'll have the new code committed soon.  I just have to fix a few other issues I created :)
Coordinator
Sep 21, 2009 at 12:50 AM
I just committed what I have.  I ran it for about 14 hours (~35k players used) and it still had some leaks, but not as bad as before.  It went up about 20 megs and about 100 handles. I'm still looking into where the other leaks could be.

Give it a test and lemme know what you see.

-Jer

Sep 21, 2009 at 2:22 PM

I have been trying to test the code for so long but always after running the build for around 2 hours, I see that you have committed new code and I have to restart again :).

In a quick glance, I can see that it has improved a lot from the previous build but I am seeing different performance in different machines. On one Windows Vista machine, I can see a lot of handle leaks. On 2 more Vista machines handle leaks are  not too much but I can see slight increase in memory. (May be codec differences). On windows XP machine, I can see that its very stable (on one machine I have tested). On Windows 7 (2 machines), there is massive increase in RAM.  

I will try to run build 28666 on multiple machines for at least 10 hours and let you know.

Coordinator
Sep 21, 2009 at 2:35 PM
I may have another build today. This one is looking good so far but only time will tell. I'll keep you updated.



On Sep 21, 2009, at 7:23 AM, jsbhatia81 <notifications@codeplex.com> wrote:

From: jsbhatia81

I have been trying to test the code for so long but always after running the build for around 2 hours, I see that you have committed new code and I have to restart again :).

In a quick glance, I can see that it has improved a lot from the previous build but I am seeing different performance in different machines. On one Windows Vista machine, I can see a lot of handle leaks. On 2 more Vista machines handle leaks are not too much but I can see slight increase in memory. (May be codec differences). On windows XP machine, I can see that its very stable (on one machine I have tested). On Windows 7 (2 machines), there is massive increase in RAM.

I will try to run build 28666 on multiple machines for at least 10 hours and let you know.

Coordinator
Sep 22, 2009 at 11:34 AM
I just did a committed a new test build.  I have had it running for almost an hour and it doesn't seem to be leaking, though it did take about ~5 minutes to see the numbers (memory and handles) plateau.

I do have some methods disabled at the moment, but if the leak is killed, I'll re-enable and test again.

Coordinator
Sep 23, 2009 at 12:06 AM
I found out what my issue was with WPF's Dispatcher.  I totally forgot to use CLSID_FilterGraphNoThread.  If you just use the CLSID_FilterGraph, it uses it's own message pump.  So I basically had two message pumps running.  CLSID_FilterGraphNoThread fixed that issue.  I'm going to move back to WPF's Dispatcher and re-enable the WndProc stuff for getting graph events vs polling that I am doing now.

There's still a small leak going on, but things are getting so much better!

Sep 25, 2009 at 11:31 AM

You just committed a release after making the default value of UnloadedBehavior in mediaElementBase to Dispose. This has created a problem in MediaUriElement in line 126. Whenever the source is changed, dispose is called and no videos are played.
But I noticed that even after that, the ffdshow was loading fine as if the graph is created but video is not displayed. Is the dispose not properly destroying the graph? or there is an issue with rendering AFTER dispose.

Sep 25, 2009 at 11:35 AM

You have also started using CLSID_FilterGraph again. Was CLSID_FilterGraphNoThread creating any other issues?

 

Coordinator
Sep 25, 2009 at 10:49 PM
I think the fix is to remove the .Dispose I added to the Element.  I believe the Close should dispose of the graph and it's thread.   The only trick I need to do is to be able to restart my dispatcher thread if the player needs to be reactivated.

On Fri, Sep 25, 2009 at 4:32 AM, jsbhatia81 <notifications@codeplex.com> wrote:

From: jsbhatia81

You just committed a release after making the default value of UnloadedBehavior in mediaElementBase to Dispose. This has created a problem in MediaUriElement in line 126. Whenever the source is changed, dispose is called and no videos are played.
But I noticed that even after that, the ffdshow was loading fine as if the graph is created but video is not displayed. Is the dispose not properly destroying the graph? or there is an issue with rendering AFTER dispose.

Read the full discussion online.

To add a post to this discussion, reply to this email (WPFMediaKit@discussions.codeplex.com)

To start a new discussion for this project, email WPFMediaKit@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com


Coordinator
Sep 26, 2009 at 1:02 AM

I think I got it.  I removed the Dispose method and enum from the MediaElementBase.  The default behavior for being unloaded from the visual tree is now "Close".  Close() will kill the media player's thread.  If a Play() or Pause() is issued after it has been killed, the WorkerDispatcherObject::EnsureThread(...) is called, ensuring the player has it's own thread and Dispatcher (WorkerDispatcher) pumping messages.

The main idea is that there should be no leaks as long as MediaElementBase::Close() is called after it is done being used.  MediaElementBase::Close() may be called automatically if Close is set as the unloaded behavior, or it will be called by a developer if it is set to manual.

I'll commit in a bit after some more testing.

Sep 26, 2009 at 10:10 AM

Is there any sequence of initialization of mediaUriElement that you are using in your internal testing?

I always keep getting exception in WorkDispatcher>>DoManagedMessageQueue>>method.DynamicInvoke(null);   "Not the same thread".

Also, can the increase in memory usage, handles be attributed to codecs as well. I was seeing different performance with different codecs before. Which video formats are you using for your testing and what codecs?

 

 

Sep 29, 2009 at 5:30 PM

Hey guys, I had the same issue about two months ago. So, would be right to say that with these new code improvements in the library, with just invoke Close() method, the same libraryis resposible for releasing pending memory or what we need in roder to do this? Ín other hand, I'm using Mainconcept codecs and I'm happy with performance results.

 

Regards.

Coordinator
Sep 29, 2009 at 8:37 PM
The newest codebase should give you much better results in the context of memory usage/leaks.  I'm seeing different results w/ different codecs myself.
Coordinator
Sep 30, 2009 at 5:31 AM
I've had this running an xvid AVI on Windows 7 for a few hours (test is similar to your first one)  outside the debugger and I have not seen a noticeable leaks.  I have been monitoring allocated handles using Windbg, and the the only handles that change are "Events", which are probably the CLR using locks for thread syncing (ie lock(...){...}).  This is why the handles go up intitially and slowly level off.  The memory usage is within one meg of where it was hours ago.


Oct 3, 2009 at 12:46 PM

I have been testing the recent build 30613 on different scenarios.

I am playing 4 videos using MediaUriElement in a window which are changed (closed and replaced) every 15 seconds. In this build I am noticing that sometimes 1 or 2 videos out of 4 won't start. Also there is great increase in handles and memory, and application reaches the OutOfmemoryException fairly quickly as compared to earlier builds. According to windbg....

The Objects of Action, Vmr9Allocator+<>c__DisplayClass1 and DsRect seems to be lurking.

I changed from

m_graph = new FilterGraph() as IGraphBuilder;

to

m_graph = new FilterGraphNoThread() as IGraphBuilder;

in MediaUriPlayer, and now the memory and handle increase is very stable, but still I am seeing that sometimes videos don't start.

Also, I tried reusing of mediaUriElement Without calling close. When I am finished with an instance I simply call stop, and put the object aside for reuse. Next time when I reuse that object and change the source, I can see the last frame of the previous video before the new video is loaded. In my opinion stop should clear the display and pause should retain the last frame. I am using Xvid for my testing.

 

 

Coordinator
Oct 3, 2009 at 11:03 PM

Thanks for the detailed report!

I have tested with both examples you provided above (samples vids from e:\users\public\videos on Windows 7) and I do not see any memory leaks.  Should I add a 4th video to the test?

Oct 4, 2009 at 1:22 PM

Hi,

Well, It does create a difference when multiple videos are playing at the same time. I have even tried 9 videos in a grid of 3x3, which is very deadly and reaches the outofmemory fairly quickly. But I reduced down my testing to 4 videos at a time.  Sample videos in Windows 7 are all wmv. In my testing I am using 4 xvid videos.

1. I start all the 4 videos with loaded and unloaded behavior to manual.

2. Change the source.

3. play all 4 mediaUriElement.

4. A timer's tick is called after every 5 sec.

5. Stop the timer tick.

5. Remove all the 4 mediaUriElement from the grid 1 by 1, call stop followed by close and then make that refernce null.

6. Recreate the mediaUriElements, add them to the grid and follow the same steps.

7. Restart the timer

You will also notice that sometimes 1 or 2 mediaUriElements don't play any videos. May be I am putting too much load but still in such a scenario, memory should be cleared when the GC is called.

Also did you notice that the MediUriElement stays at the last frame when the video is stopped? the display should be cleared on stop.

Also, the situation improves when I use Filtergraphnothread. Was there a specific reason, you changed it back to filtergraph??

Coordinator
Oct 5, 2009 at 2:42 AM
Edited Oct 5, 2009 at 2:59 AM

I changed the controls now to honor the ISupportInitialize interface (Implemented on FrameworkElement w/ overridden methods).  This is a change I've been meaning to do for a while.  This makes it XAML parser friendly and greatly simplifies my code and makes things more predictable.  So when you use a control via code, BeginInit flags a batch change for the control.  EndInit applies the changes.

Memory/handles aren't necessarily to be be released on a GC call.  Remember there are a lot of threads (even ones we don't create) running, with native memory allocations and COM instances that the GC doesn't even know about.  Not mention behaviors like this:  http://blogs.msdn.com/junfeng/archive/2008/04/28/event-handles-leak.aspx

I changed it to FilterGraph because it didn't make any difference on my machine at all if I used NoThread.  If you say it runs better with NoThread, I'll leave it the default.  I have the newest code committed.  

Here is the code for my test based on your previous:

Codebehind:

 

    public partial class TestMultipleVideosChangingReuseMediaUriElement : Window
    {
        DispatcherTimer _timer = new DispatcherTimer();
        private List<MediaUriElement> m_players = new List<MediaUriElement>();
        private List<string> _listOfVideoFiles;
        private int _playerToStartStopNext = 0;
        
        private const int MAX_PLAYERS = 5;
        private bool REUSE_PLAYERS = true;

        public TestMultipleVideosChangingReuseMediaUriElement()
        {
            InitializeComponent();
        }
        
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            CreateMediaUriElements();
            StartStopMediaUriElements();

            _timer.Interval = TimeSpan.FromSeconds(1);
            _timer.Tick += Timer_Tick;
            _timer.Start();
        }

        private string GetRandomFileFromDirectory()
        {
            if (_listOfVideoFiles == null)
            {
                string directory = @"e:\users\public\videos";
                _listOfVideoFiles = new List<string>();

                string[] files1 = Directory.GetFiles(directory, "*.avi", SearchOption.AllDirectories);
                string[] files2 = Directory.GetFiles(directory, "*.wmv", SearchOption.AllDirectories);
                string[] files3 = Directory.GetFiles(directory, "*.mkv", SearchOption.AllDirectories);

                _listOfVideoFiles.AddRange(files1);
                _listOfVideoFiles.AddRange(files2);
                _listOfVideoFiles.AddRange(files3);
            }

            var random = new Random();
            int i = random.Next(0, _listOfVideoFiles.Count - 1);
            return _listOfVideoFiles[i];
        }

        private void CreateMediaUriElements()
        {
            for (int i = 0; i < MAX_PLAYERS; i++)
            {
                m_players.Add(new MediaUriElement{Width=160, Height=120});
            }
        }

        private void StartStopMediaUriElements()
        {
            var player = m_players[_playerToStartStopNext];

            int pos = panel.Children.IndexOf(player);
            panel.Children.Remove(player);
            
            if (pos < 0)
                pos = panel.Children.Count;
            else if(!REUSE_PLAYERS)
            {
                m_players[_playerToStartStopNext] = new MediaUriElement{ Width = 160, Height = 120 };
                player = m_players[_playerToStartStopNext];
            }

            player.BeginInit();
            player.Source = new Uri(GetRandomFileFromDirectory());
            panel.Children.Insert(pos, player);
            player.EndInit();

            Debug.WriteLine(player.Source.OriginalString);

            _playerToStartStopNext++;

            if (_playerToStartStopNext > MAX_PLAYERS - 1)
            {
                _playerToStartStopNext = 0;
            }
        }

        private void Timer_Tick(object sender, EventArgs e)
        {
            StartStopMediaUriElements();
            GC.Collect(2);
            GC.WaitForPendingFinalizers();
            GC.Collect(2);
        }
    } 

XAML:

 

<Window x:Class="SampleApplication.TestMultipleVideosChangingReuseMediaUriElement"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="TestMultipleVideosChangingReuseMediaUriElement"
        Height="600"
        Width="800"
        Loaded="Window_Loaded">
    <WrapPanel x:Name="panel" />
</Window>

 

 

 

Coordinator
Oct 6, 2009 at 8:56 AM

I just did another commit.  I noticed with wmv files, it would leak as you described, or crash.  I analyzed the crash to be this:

WMVDECOD!CWMVideoObjectDecoder::DecodeInverseInterBlockQuantize16_DXVAC+8dd in C:\Windows\SysWOW64\WMVDECOD.DLL from Microsoft Corporation has caused an access violation exception (0xC0000005) when trying to write to memory location 0x00000000 on thread 104

I have a hunch that DXVA enabled formats are causing this because a non-DXVA XVID AVI would not leak or crash.

I made some changes to the VMR9 allocator and rebooted my computer (In case of a driver leak too) and it's been running ok so far.  We'll see in the morning.

Oct 8, 2009 at 10:51 AM

ok, I have noticed 2 things that I can say concretely.

1. Most of the exceptions that i see now are of crashes in libavcodec or ffdshow, and these exceptions are not predictable. Videos could be playing for hours or sometimes days before the exception window pops up (or it could be just a few minutes. Can these exceptions be catched and handled in code rather than exception window popping up??

2. After you have implemented ISupportInitialize, the mediaOpened event is firing twice if I use begininit and endinit.

Coordinator
Oct 8, 2009 at 11:20 AM
Thanks for the info!

Ill look into the media opened issue.

What codecs are you using with ffdshow?  I had tested for 30 hours and no crashes.   This was on an xvid avi using the sample test I posted earlier. I manually added ffdshow to the graph (see latest mediauriplayer code, i have it commented) to ensure it would use this codec.  I'll have to look into if you can trap those errors.  Might be hard as they are coming from native code.

I was still getting crashes when I would do WMV files that were DXVA accelerated.  I made a few changes (committed) and now the D3D surface gets released for D3DImage on the dispose of the vmr9 allocator and my WMV test didn't crash or leak in the 3 hours I ran it (usually took 30 mins - 45 mins).  I'm going to run it over night and see how it does.
Coordinator
Oct 8, 2009 at 11:25 AM
Also in my testing, I've removed the GC collects and just monitor it in performance monitor (handlecount + private bytes).

In ffdshow I've turned off the tray icons.  Maybe try disabling the "Drop frame on delay" in the "Decoder options" of ffdshow config also.  Might not do anything, but I wanted to see if our setups closely matched so we can see the same issues.
Oct 8, 2009 at 12:59 PM

Well, I have now disabled the tray icons in ffdshow audio and video and also disabled the "Drop frame on delay". Lets see what happens.

After you told the bug in wmv dxva enabled formats, I reduced the testing to xvid/divx. Couple of my systems where I see the crash in ffdshow.ax are running K-lite codec pack with ffdshow tryout revision 3092. When I load the same file in graphedit, all I see is AVISplitter-->ffdshow video decoder-->VMR video renderer.

There is new version of ffdshow released, I will update my systems with new version if the error comes again.

I saw that you manually added ffdshow to the graph but your comment said its for testing. After testing, I think it should be left to system defaults, if the user chooses to bypass it.

Oct 10, 2009 at 9:06 AM

ffdshow tray icons and "Drop frame on delay" are disabled but still I have got the exception window saying "Program has stopped working" pointing towards ffdshow.ax after about 36 hours. Although I can see that the videos are playing in the background as per my logic (changing every 5 seconds), but still the exception window(Dr Watson, I guess) stays at top.

I know that after about 36 hours (time is random as I said in the earlier post), one of my MediaUriElement would have got this exception while loading a file. Being a com object, it wasn't consumed by the code and was shown as a window on desktop.

I don't thing, its an issue with your mediakit. Infact this library is excellent and very stable now for xvid/divx (will check other formats now). I used to get this ffdshow.ax exceptions earlier when I was using .net 3.5's mediaelement or mediaplayer as well.

I don't know much about com objects and interop, but is there a way you can consume or handle such rare exception in external filters?

Coordinator
Oct 11, 2009 at 1:33 AM

Thanks so much for helping test this.  This thread has been great motivation for fixing some long standing issues.

I have made another comitted change.  It should no longer run the media opened event twice, but alas, the syntax had to change once again.

 

 

player.BeginInit();
player.Source = new Uri(GetRandomFileFromDirectory());
player.EndInit();
panel.Children.Insert(pos, player);

I came across another person having the same crashing problems with Windows Media codecs, except he was just using the WPF MediaElement thousands of times.  I'm going to submit a bug report to the Microsoft Connect site.

 

 

 

            player.BeginInit();
            player.Source = new Uri(GetRandomFileFromDirectory());
            player.EndInit();
            panel.Children.Insert(pos, player

 

Coordinator
Oct 11, 2009 at 7:12 AM
Edited Oct 11, 2009 at 7:15 AM

I'm going to give this a shot and see if it will trap the unmanaged exception I was getting:

http://msdn.microsoft.com/en-us/library/system.windows.forms.application.setunhandledexceptionmode.aspx

EDIT:

Or the WPF one that might be the same: http://msdn.microsoft.com/en-us/library/system.windows.application.dispatcherunhandledexception.aspx

May 9, 2011 at 11:56 AM
Sorry to bring this thread up from the dead but I am experiencing these issues and was wondering whether there is a way round it?
I am loading a lot of movies (about 10 at a time every 5 seconds for testing purposes). When my user control closes, I am setting the movie to stop and close and setting the source to null but I still get a crash after a few hours. The movies are wmv's, is here a better alternative?
Sep 18, 2011 at 6:13 PM

hey,

i've been having this problem too. the application randomly crashes saying that the "application has stopped responding".

did you manage to find a fix for this issue?

Sep 18, 2011 at 9:22 PM

Hi roidimor,

 

No, I never found a fix but it didn't turn out to be a major issue for me. I had to load a hell of a lot of movies before the I got a crash. The application I was working on gets turned off after about 8 hours so there is never really enough time for users to load that many movies.

It would be nice to know if there is a way around it though.

Sep 18, 2011 at 9:54 PM

:(

well my application is supposed to run for months, so it's kind of problematic for me.

if i won't find a solution soon i would have no choice but trying http://vlcdotnet.codeplex.com/ :(

jmorrill, is there a chance you found out what's causing the crashes?

Sep 25, 2011 at 10:52 PM
Edited Sep 25, 2011 at 10:57 PM

Try something like this:

using System.Runtime.ExceptionServices;  // .NET4
        [HandleProcessCorruptedStateExceptions]
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                player.Stop();
                player.Close();
                GC.Collect(2);
                GC.WaitForPendingFinalizers();
                GC.Collect(2);
                player.BeginInit();
                player.Source = new Uri(path);
                player.EndInit();
                player.Play();
                GC.Collect(2);
                GC.WaitForPendingFinalizers();
                GC.Collect(2);
            }
            catch (Exception)
            {
            }
        }
http://dotnetslackers.com/articles/net/All-about-Corrupted-State-Exceptions-in-NET4.aspx
you can also try marking your assembly as  [assemblySecurityCritical]but i can't remember if this is really critical/needed.
I have had pretty good success with the above.....

Good luck.

--dave
http://dave.thehorners.com/
Dec 24, 2011 at 8:42 AM

well, i keep getting those exceptions. has anyone managed to solve this?

May 27, 2014 at 8:42 AM
Hi roidimor,

Just wondering whether you ever managed to solve this issue or whether you went with a different library?
May 28, 2014 at 10:15 PM
c_h_r_i_s wrote:
Hi roidimor,

Just wondering whether you ever managed to solve this issue or whether you went with a different library?
hey,
i never managed to solve it. eventually i went with VlcDotNet which works pretty well for almost two and a half years now.