Crash when disposing MediaPlayer
Summary
- My app crashes with a Unity crash handler popup window and below stack trace in Unity's Player.log file.
- I found that the crash occurs when calling MediaPlayer.Dispose.
- Further, I found a workaround by calling Thread.Sleep before calling MediaPlayer.Dispose.
Minimal project and steps to reproduce
I can reproduce the crash with a Unit test in the Unity editor in my project. However, this code is not open source (yet).
What my Unit test does is roughly the following:
- load a video file via libVLC
- init libVLC if not done yet
- create a MediaPlayer object
- set the Media object of the MediaPlayer
- call MediaPlayer.PlayAsync()
- wait until a valid duration for the loaded file is returned by libVLC
- if the duration is returned within reasonable time (e.g. 1 second), then the test passes. Otherwise, the test fails.
- afterwards the MediaPlayer is disposed
- here, the crash happens in some situations
Above test procedure is done for multiple file formats, e.g. mkv, flv, f4v.
I noticed that the crash only happens when multiple such test cases are executed in sequence. The issue does not occur when only a single test case is executed.
Using the Unit test, I found that the crash is related to calling MediaPlayer.Dispose. Further, I found a workaround (see below).
What is the current bug behavior?
A crash happens after calling MediaPlayer.Dispose
What is the expected correct behavior?
No crash should happen when calling MediaPlayer.Dispose. libVLC should either
- throw a proper exception when preconditions for disposing are not met,
- or establish required preconditions by itself.
Does it work on other plaforms? Does it work with the official VLC apps?
Crash happens on Windows. Other platforms have not been tested.
Relevant logs and/or screenshots
Excerpt of Unity's Player.log file:
========== OUTPUTTING STACK TRACE ==================
0x00007FF8648E2EA7 (VLCUnityPlugin) GetRenderEventFunc
0x00007FF8648E2115 (VLCUnityPlugin) GetRenderEventFunc
0x00007FF816BB3F9D (libdirect3d11_plugin) vlc_entry_license
0x00007FF816BB1E9F (libdirect3d11_plugin) vlc_entry
0x00007FF82B8F0B0A (libvlccore) vout_display_New
0x00007FF82B900E2E (libvlccore) vlc_gl_surface_Destroy
0x00007FF82B8F431A (libvlccore) vout_Hold
0x00007FF82B8E1BF6 (libvlccore) input_resource_Release
0x00007FF82B8BBC94 (libvlccore) vlc_input_decoder_SetSpuHighlight
0x00007FF82B8BE4B2 (libvlccore) decoder_UpdateVideoOutput
0x00007FF8173E1ED6 (libavcodec_plugin) Ordinal0
0x00007FF8173E23F5 (libavcodec_plugin) Ordinal0
0x00007FF817410401 (libavcodec_plugin) vlc_entry_license
0x00007FF817720359 (libavcodec_plugin) vlc_entry_license
0x00007FF81771AAA7 (libavcodec_plugin) vlc_entry_license
0x00007FF81771646E (libavcodec_plugin) vlc_entry_license
0x00007FF817824220 (libavcodec_plugin) vlc_entry_license
0x00007FF8178243AF (libavcodec_plugin) vlc_entry_license
0x00007FF8F3A2AF5A (msvcrt) beginthreadex
0x00007FF8F3A2B02C (msvcrt) endthreadex
0x00007FF8F27B7344 (KERNEL32) BaseThreadInitThunk
0x00007FF8F44426B1 (ntdll) RtlUserThreadStart
========== END OF STACKTRACE ===========
Note that this stack trace is the same as in #121 However, my set up is different (play vs. dispose) such that I decided to create a dedicated issue. Issues may be related, don't know.
Environment
- OS: Windows 11
- LibVLC version and architecture: 4.0.0-dev-24970-ga03de829e1
- LibVLCSharp version: LibVLCSharp version: 4.0.0.0
- VLC Unity plugin version: 0.1.8
- Scripting backend used: Mono
Possible fixes
I expected the issue to be timing related, which is why I played around with Thread.Sleep. Indeed, I found that the issue can be worked around by sleeping long enough before calling MediaPlayer.Dispose. Further, I found that the workaround only works when called BEFORE Dispose.
Thus, I think the issue may be caused by calling dispose while libVLC is still loading media content. IMO, such a case should be handled by libVLC more gracefully.
Task.Run(() =>
{
// Calling Thread.Sleep to prevent crash in libVLC.
// Note that the workaround only works when Thread.Sleep is called BEFORE calling Dispose.
Thread.Sleep(1000);
mediaPlayer.Dispose();
});