Skip to content
This repository has been archived by the owner on Jan 21, 2022. It is now read-only.

Reworked VlcManager architecture #490

Merged

Conversation

jeremyVignelles
Copy link
Collaborator

@jeremyVignelles jeremyVignelles commented Nov 22, 2018

to ensure proper loading/unloading of libvlc*.dll

Fixes #482
Fixes #389
Replaces #486

A few words about the implementation :

  • Removed useless VlcInteropsManager abstract class

  • Introduced a VlcLibraryLoader class : It loads the DLL files and DLL functions. Static methods are there to ensure that only one instance is there per path, and that the DLL is properly unloaded when it's not needed anymore.

  • VlcManager is not tied to a dll path anymore (it's VlcLibraryLoader's job). Instead it's tied to a VlcInstance, i.e. libvlc_new

  • libvlc instances are not cached anymore: This means that two different players can (will by default) use two different libvlc instances, each having potentially different media player options

  • VlcManager.CreateNewInstance does not exist anymore : instead, arguments are passed to VlcManager's constructor and libvlc instance is created in the constructor.

  • This means that EnsureVlcInstance is not needed anymore.

  • Behavior changed : No options are passed to the MediaPlayer by default. To restore previous behavior, set:

#if DEBUG
            var option = new[]
            {
                "--extraintf=logger",
                "--verbose=2"
            };
#else
            var options = new[]
            {
                "--quiet"
            };
#endif
  • MISC : WinForms Control now throws on invalid VlcMediaPlayerOptions/VlcLibDirectory usage.

/cc @dilandau2001

@dilandau2001
Copy link
Contributor

Hi. I saw your message. I am currently without computer. I would like to check out your branch to give it a look but it would not be soon.

@jeremyVignelles
Copy link
Collaborator Author

Thanks for your answer. I'm currently out for holidays and will return on december the 1st.
I'm interested in your feedback anyway, even if it's later, don't worry

@jeremyVignelles
Copy link
Collaborator Author

Hi @dilandau2001 , any time for a review?

@dilandau2001
Copy link
Contributor

Today, I will give it a try. sorry for the delay

@dilandau2001
Copy link
Contributor

I did a test with this code.

I used sample: MultiplePlayers.
The test steps were:
1- Create 1 player
2- Destroy it
3- Get memory snapsot

I did it multiple times.

I could reproduce a small and consistent leak but I haven't being able yet to identify the leak as apparently handlers are bein unregistered correctly.

image

Also VlcControl.EndInit has become a bit slower than before. Don't know the reason either. I would sepparate the part of the code that requires to run in the ui thread (apparently only the handle assingn) from the part of the code that can run in a different thread so the time the ui is blocked is reduced to the minimum.

@jeremyVignelles
Copy link
Collaborator Author

Thanks for the review!

Also VlcControl.EndInit has become a bit slower than before.

Seems quite normal : the libvlc instance is not shared anymore, which means we need to call libvlc_new each time, but which brings the benefit of being able to pass different parameters.

You can still create a new media player with a shared VlcManager if you want, because this constructor is now public. https://github.com/ZeBobo5/Vlc.DotNet/pull/490/files#diff-478680d15152ff2c027403f8f9ee05c9R24.

For the leak, I did try that and noticed the same thing. However, I'm not a memory leak expert, and concluded that the leak wasn't meanignful and was likely caused by the runtime or the environment and was normal.

If you think that something is wrong, we will need to dig deeper. Can that be an issue on libvlc's side?

@jeremyVignelles
Copy link
Collaborator Author

I would sepparate the part of the code that requires to run in the ui thread (apparently only the handle assingn) from the part of the code that can run in a different thread so the time the ui is blocked is reduced to the minimum.

Is it really long? Do we really need to do something about it? Spawning a thread/awaiting something in the constructor feels dangerous (race conditions, hard error catching...) for me without a good reason.

@dilandau2001
Copy link
Contributor

Testing performance, starting and closing players several times I could reproduce the following crash:

Faulting application name: Samples.WinForms.MultiplePlayers.exe, version: 0.0.0.0, time stamp: 0xba087546
Faulting module name: ntdll.dll, version: 10.0.17134.376, time stamp: 0x60d78cf9
Exception code: 0xc0000374
Fault offset: 0x00000000000f4d7b
Faulting process ID: 0x14e8
Faulting application start time: 0x01d490da2698128c
Faulting application path: D:\PROJECTS\Vlc.DotNetUpdate\src\Samples\Samples.WinForms.MultiplePlayers\bin\Debug\Samples.WinForms.MultiplePlayers.exe
Faulting module path: C:\WINDOWS\SYSTEM32\ntdll.dll
Report ID: afa3dbbd-e0d2-4804-ab04-438a0efc6442
Faulting package full name:
Faulting package-relative application ID:

@dilandau2001
Copy link
Contributor

I did a small variation of the test:

Living always one player running.
1 - Create a second player,
2 - Destroy it
3 - Get snapshot:

With x64 VLC 3.04 version results:
image

ntdll.dll crash when 10 players playing.

With x64 VLC 2.2.4 version results:

image

memory still leaks.
But at least there is no ntdll.dll crash.

The thing is, I think the previous code was not leaking over time.
I will have to test if over time (long time) the memory stabilizes

@dilandau2001
Copy link
Contributor

I was wrong, old code leaks the same amount...
At least it seems to be under control because it is not the exact same amount per closed player.
A good test would be to leave a test running for a day opening and closing players.

@dilandau2001
Copy link
Contributor

Is it really long? Do we really need to do something about it? Spawning a thread/awaiting something in the constructor feels dangerous (race conditions, hard error catching...) for me without a good reason.

Well, it depends what is the source of the leak. If it is leaking handlers then that will eventually rise an outofmemory exception. If it is rubbish for the GC to work with then you can survive with it.

@jeremyVignelles
Copy link
Collaborator Author

The architecture of this PR is where I want to go with Vlc.DotNet : the Libvlc instance is not shared anymore, allowing it to be released properly and passing different options.

Sharing libvlc instance leaks only one instance per run, but that doesn't mean that the code is better IMHO.

We need to fix that crash before merging

@dilandau2001
Copy link
Contributor

Can you reproduce the crash in your environment?... just opening 10-15 players with Vlc 3.0.4.
And it does not crash with 2.2.4.
If it happens to you as well I would say it is an issue of vlclib itself as ntdll.dll is something quite deep in Windows system.

@jeremyVignelles
Copy link
Collaborator Author

I didn't have time to try it yet. ntdll doesn't really mean anything since it's used everywhere...

@jeremyVignelles
Copy link
Collaborator Author

Despite my tests, I couldn't reproduce this on my windows 10... Anyone else reproduces the crash? Anyone else can try this?

I launched a debug session of Sample.WinForms.MultiplePlayers, added many players, removed many players, repeated... no crash...

@jeremyVignelles
Copy link
Collaborator Author

@dilandau2001: which windows version?

@dilandau2001
Copy link
Contributor

I did my tests with Windows 10

@mfkl
Copy link
Contributor

mfkl commented Dec 12, 2018

@dilandau2001 Can you share your full code for repro please?

@hasanghaddar
Copy link

hasanghaddar commented Dec 14, 2018

@jeremyVignelles I am facing this issue also , and tested on Windows 10 and Windows server 2012 r2

to ensure proper loading/unloading of libvlc*.dll

Fixes ZeBobo5#482
Now waiting asynchronously rather that blocking the ThreadPool's thread.
@jeremyVignelles
Copy link
Collaborator Author

I'm back with this PR after a long time!

@dilandau2001 , After testing, I disagree with that part:

Also VlcControl.EndInit has become a bit slower than before.

With this code in MultiplePlayers.Forms1:

                    panel.Controls.Add(player);
                    var sw = new Stopwatch();
                    sw.Start();
                    player.EndInit();
                    Debug.WriteLine($"Elapsed {sw.ElapsedMilliseconds}ms");

Before this PR:

Elapsed 595ms
Elapsed 468ms
Elapsed 1037ms
Elapsed 1142ms

After:

Elapsed 422ms
Elapsed 9ms
Elapsed 10ms
Elapsed 12ms

I guess we could do better if we passed the media player to the control, but I think it is acceptable as-is.

I still can't reproduce your crash... can you try to clean your code? Are you on a x86 windows? I can't figure out what's the difference between your machine and mine. If anyone has a clue, he's welcome...

@dilandau2001
Copy link
Contributor

I will do a retry as soon as I can.
Mine is a Windows 10 x64 SO

@jeremyVignelles
Copy link
Collaborator Author

@dilandau2001 Did you have time to have a look at this?

@dilandau2001
Copy link
Contributor

dilandau2001 commented Jan 24, 2019 via email

@dilandau2001
Copy link
Contributor

Hello

I gave it another try.
I don't see evident memory leak nor event handlers left behind so that is good news.
But I could consistently reproduce the crash.
Using this pull code with Vlc libs coming from VLC 3.0.6.

This is how I did it:
Project 1.zip : Video of error.

Reproduction steps:

  • Open 12-14 players very fast of a local file
  • let them play until end of video, it gets frozen. :input-repeat=-1 does not work fine with small videos.
  • Close them very fast too.

Notes:
The video is quite small, less than 10 seconds and it gots frozen at the end of it as loop does not work fine with short videos.

Tips:
To be honest, what I finally came up doing for multiple players was to run each player on its own executable and link each window on the desirable parent. So if one player crashes main application can survive and restart it, and also you are no longer limitted by one single process memory limit.

@jeremyVignelles
Copy link
Collaborator Author

Hello, thanks for the explanations, will try that. is that possible that the crash comes from libvlc itself? frozen video is not a good sign.
does the crash happen with the current develop version?

Your solution of making child process is good for video wall applications (I'm using this technique too) but doesn't apply to all cases, when video are embedded in a GUI for example.

@dilandau2001
Copy link
Contributor

dilandau2001 commented Jan 28, 2019

Well I actually embed the videos inside my Gui using Win32 SetParent functions and similar things. Only for Windows Forms though.

Regarding the crash. It did not happen in vlc 2.2.4 so it seems something from vlc itself.

@jeremyVignelles jeremyVignelles merged commit fb42e9a into ZeBobo5:develop Jan 30, 2019
@jeremyVignelles jeremyVignelles deleted the fix/vlcmanager-rework branch February 27, 2019 19:06
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants