LibVLCSharp WPF MediaPlayer.Dispose() hangs
So I'm trying to clean up my media player stack, and my call to MediaPlayer.Dispose() goes off into lala land and never comes back.
I have a class that inherits from VideoView as such, and when I call the cleanup() function it never returns:
using System;
using System.Windows;
using LibVLCSharp.Shared;
using MediaPlayer = LibVLCSharp.Shared.MediaPlayer;
namespace MyNamespace.Videocontrols
{
/// <summary>
/// Implements a wrapper class around the LibVLCSharp WPF VideoView Control.
/// This class is primarily implemented as a way to provide properties and default
/// actions that can be set within the xaml construction.
///
/// Usage:
/// <vlcControl Source="{Binding AnimationFile}" LoadedBehavior="Play" MediaEnded="animationPlayer_MediaEnded" MediaFailed="animationPlayer_MediaFailed"/>
/// </summary>
public class vlcPlayer : LibVLCSharp.WPF.VideoView
{
public LibVLC _libVLC;
public vlcPlayer()
{
_libVLC = new LibVLC();
MediaPlayer = new MediaPlayer(_libVLC);
}
~vlcPlayer()
{
}
// I'm implementing this Cleanup() routine because I need to dispose of these resources
// Waaaaaay before the garbage collector can come in and destruct this vlcplayer object
// since this object sucks up a butt-ton of resources. Once the video has played and
// I've hidden this object, I need to free up these resources.
public void Cleanup()
{
if (!MediaPlayer.IsPlaying)
MediaPlayer.Media.Dispose();
MediaPlayer.Dispose();
_libVLC.Dispose();
}
public void PlayVideo()
{
// Set handlers, if any are defined
if (MediaEnded != null)
{
MediaPlayer.EndReached += MediaEnded;
}
else
{
// Don't allow not defining a mediaEnded action
throw (new NotImplementedException());
}
if (MediaFailed != null)
{
MediaPlayer.EncounteredError += MediaFailed;
}
else
{
// Don't allow not defining a mediaFailed action
throw (new NotImplementedException());
}
if (Source != null)
{
if (!MediaPlayer.IsPlaying)
{
var mediaObject = new Media(_libVLC, Source, Media.FromType.FromPath);
MediaPlayer.Play(mediaObject);
}
}
}
public enum LoadedBehaviorTypes
{
Play,
Manual
}
public static readonly DependencyProperty LoadedBehaviorProperty =
DependencyProperty.Register(
"LoadedBehavior", typeof(LoadedBehaviorTypes),
typeof(vlcPlayer)
);
public LoadedBehaviorTypes LoadedBehavior
{
get { return (LoadedBehaviorTypes)GetValue(LoadedBehaviorProperty); }
set { SetValue(LoadedBehaviorProperty, value); }
}
public static readonly DependencyProperty MediaEndedProperty =
DependencyProperty.Register(
"MediaEnded", typeof(EventHandler<EventArgs>),
typeof(vlcPlayer)
);
public EventHandler<EventArgs> MediaEnded
{
get { return (EventHandler<EventArgs>)GetValue(MediaEndedProperty); }
set { SetValue(MediaEndedProperty, value); }
}
public static readonly DependencyProperty MediaFailedProperty =
DependencyProperty.Register(
"MediaFailed", typeof(EventHandler<EventArgs>),
typeof(vlcPlayer)
);
public EventHandler<EventArgs> MediaFailed
{
get { return (EventHandler<EventArgs>)GetValue(MediaFailedProperty); }
set { SetValue(MediaFailedProperty, value); }
}
public static readonly DependencyProperty MediaPlayerObjectProperty =
DependencyProperty.Register(
"MediaPlayerObject", typeof(LibVLCSharp.Shared.MediaPlayer),
typeof(vlcPlayer)
);
public LibVLCSharp.Shared.MediaPlayer MediaPlayerObject
{
get { return (LibVLCSharp.Shared.MediaPlayer)GetValue(MediaPlayerObjectProperty); }
set { SetValue(MediaPlayerObjectProperty, value); }
}
public static readonly DependencyProperty LibVLCObjectProperty =
DependencyProperty.Register(
"LibVLCObject", typeof(LibVLCSharp.Shared.LibVLC),
typeof(vlcPlayer)
);
public LibVLCSharp.Shared.LibVLC LibVLCObject
{
get { return (LibVLCSharp.Shared.LibVLC)GetValue(LibVLCObjectProperty); }
set { SetValue(LibVLCObjectProperty, value); }
}
public static readonly DependencyProperty SourceProperty =
DependencyProperty.Register(
"Source", typeof(string),
typeof(vlcPlayer)
);
public string Source
{
get { return (string)GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); }
}
}
}
My xaml then becomes fairly trivial (I'm not showing storyboards, btw), as such:
<Grid x:Name="video" Margin="0,0,0,0" Visibility="Hidden">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<local:vlcPlayer
Grid.Column="0" Grid.Row="0"
HorizontalAlignment="Center" VerticalAlignment="Center"
Height="720" Width="1280"
Source="{Binding AnimationFile}" LoadedBehavior="Play"
MediaEnded="animationPlayer_MediaEnded" MediaFailed="animationPlayer_MediaFailed"
x:Name="vlcPlayer"/>
</Grid>
And my xaml.cs back-end code is pretty straightforward as well:
public partial class myView : UserControl
{
public myView()
{
InitializeComponent();
Loaded += OnLoad;
}
private void OnLoad(object sender, RoutedEventArgs e)
{
// Starts hidden to reduce flicker on load
video.Visibility = Visibility.Visible;
vlcPlayer.PlayVideo();
}
private void animationPlayer_MediaEnded(object sender, EventArgs e)
{
this.Dispatcher.Invoke(() =>
{
Storyboard sb1 = (Storyboard)TryFindResource("Storyboard1");
if (sb1 != null)
sb1.Begin();
video.Visibility = Visibility.Hidden;
vlcPlayer.Cleanup();
});
}
private void animationPlayer_MediaFailed(object sender, EventArgs e)
{
this.Dispatcher.Invoke(() =>
{
Storyboard sb2 = (Storyboard)TryFindResource("Storyboard2");
if (sb2 != null)
sb2.Begin();
video.Visibility = Visibility.Hidden;
vlcPlayer.Cleanup();
});
}