Commit 4633523b authored by Martin Finkel's avatar Martin Finkel

Remove LibVLC from VideoView and uncouple MediaPlayer from the view lifecycle

parent 05debdd8
using LibVLCSharp.Shared; using LibVLCSharp.Shared;
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Forms.Integration; using System.Windows.Forms.Integration;
...@@ -17,21 +18,38 @@ namespace LibVLCSharp.WPF ...@@ -17,21 +18,38 @@ namespace LibVLCSharp.WPF
public VideoView() public VideoView()
{ {
DefaultStyleKey = typeof(VideoView); DefaultStyleKey = typeof(VideoView);
}
private void Attach()
{
if (!IsDesignMode) if (!IsDesignMode)
{ {
Core.Initialize(); if (MediaPlayer == null)
{
Trace.Write("No MediaPlayer is set, aborting...");
return;
}
LibVLC = new LibVLC(); var hwnd = (Template.FindName(PART_PlayerView, this) as System.Windows.Forms.Panel)?.Handle;
MediaPlayer = new MediaPlayer(LibVLC); if (hwnd == null)
{
Trace.WriteLine("HWND is NULL, aborting...");
return;
}
Unloaded += VideoView_Unloaded; MediaPlayer.Hwnd = (IntPtr)hwnd;
} }
} }
~VideoView() private void Detach()
{ {
Dispose(); if (!IsDesignMode)
{
if (MediaPlayer != null)
{
MediaPlayer.Hwnd = IntPtr.Zero;
}
}
} }
private bool IsDesignMode => (bool)DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(DependencyObject)).DefaultValue; private bool IsDesignMode => (bool)DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(DependencyObject)).DefaultValue;
...@@ -39,12 +57,23 @@ namespace LibVLCSharp.WPF ...@@ -39,12 +57,23 @@ namespace LibVLCSharp.WPF
private bool IsUpdatingContent { get; set; } private bool IsUpdatingContent { get; set; }
private UIElement ViewContent { get; set; } private UIElement ViewContent { get; set; }
public MediaPlayer MediaPlayer { get; private set; } private MediaPlayer _mediaPlayer;
public LibVLC LibVLC { get; private set; } public MediaPlayer MediaPlayer
private void VideoView_Unloaded(object sender, RoutedEventArgs e)
{ {
Dispose(); get => _mediaPlayer;
set
{
if (_mediaPlayer != value)
{
Detach();
_mediaPlayer = value;
if (_mediaPlayer != null)
{
Attach();
}
}
}
} }
public override void OnApplyTemplate() public override void OnApplyTemplate()
...@@ -56,14 +85,10 @@ namespace LibVLCSharp.WPF ...@@ -56,14 +85,10 @@ namespace LibVLCSharp.WPF
var windowsFormsHost = Template.FindName(PART_PlayerHost, this) as FrameworkElement; var windowsFormsHost = Template.FindName(PART_PlayerHost, this) as FrameworkElement;
if (windowsFormsHost != null) if (windowsFormsHost != null)
{ {
ForegroundWindow = new ForegroundWindow(windowsFormsHost); ForegroundWindow = new ForegroundWindow(windowsFormsHost)
ForegroundWindow.Content = ViewContent; {
} Content = ViewContent
};
var hwnd = (Template.FindName(PART_PlayerView, this) as System.Windows.Forms.Panel)?.Handle;
if (hwnd != null)
{
MediaPlayer.Hwnd = (IntPtr)hwnd;
} }
} }
} }
...@@ -94,24 +119,29 @@ namespace LibVLCSharp.WPF ...@@ -94,24 +119,29 @@ namespace LibVLCSharp.WPF
} }
} }
public void Dispose() #region IDisposable Support
{
Unloaded -= VideoView_Unloaded;
if (MediaPlayer != null) bool disposedValue;
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{ {
if (MediaPlayer.IsPlaying) if (disposing)
MediaPlayer.Stop(); {
MediaPlayer.Hwnd = IntPtr.Zero; Detach();
MediaPlayer.Dispose(); }
MediaPlayer = null;
}
if (LibVLC != null) ViewContent = null;
{ ForegroundWindow = null;
LibVLC.Dispose();
LibVLC = null; disposedValue = true;
} }
} }
public void Dispose()
{
Dispose(true);
}
#endregion
} }
} }
\ No newline at end of file
...@@ -14,30 +14,60 @@ namespace LibVLCSharp.Platforms.Android ...@@ -14,30 +14,60 @@ namespace LibVLCSharp.Platforms.Android
public class VideoView : SurfaceView, IVLCVoutCallback, IVideoView public class VideoView : SurfaceView, IVLCVoutCallback, IVideoView
{ {
MediaPlayer _mediaPlayer; MediaPlayer _mediaPlayer;
LibVLC _libVLC;
AWindow _awindow; AWindow _awindow;
LayoutChangeListener _layoutListener; LayoutChangeListener _layoutListener;
#region ctors #region ctors
public VideoView(IntPtr javaReference, JniHandleOwnership transfer, string[] cliOptions = default (string[])) : base(javaReference, transfer) => Init(cliOptions); public VideoView(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{
}
public VideoView(Context context, string[] cliOptions = default(string[])) : base(context) => Init(cliOptions); public VideoView(Context context) : base(context)
{
}
public VideoView(Context context, IAttributeSet attrs, string[] cliOptions = default(string[])) : base(context, attrs) => Init(cliOptions); public VideoView(Context context, IAttributeSet attrs) : base(context, attrs)
{
}
public VideoView(Context context, IAttributeSet attrs, int defStyleAttr, string[] cliOptions = default(string[])) : base(context, attrs, defStyleAttr) => Init(cliOptions); public VideoView(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr)
{
}
public VideoView(Context context, IAttributeSet attrs, int defStyleAttr, int defStyleRes, string[] cliOptions = default(string[])) public VideoView(Context context, IAttributeSet attrs, int defStyleAttr, int defStyleRes)
: base(context, attrs, defStyleAttr, defStyleRes) => Init(cliOptions); : base(context, attrs, defStyleAttr, defStyleRes)
{
}
#endregion #endregion
public LibVLCSharp.Shared.MediaPlayer MediaPlayer => _mediaPlayer; /// <summary>
public LibVLC LibVLC => _libVLC; /// The MediaPlayer object attached to this VideoView. Use this to manage playback and more
/// </summary>
public MediaPlayer MediaPlayer
{
get => _mediaPlayer;
set
{
if (_mediaPlayer != value)
{
Detach();
_mediaPlayer = value;
if (_mediaPlayer != null)
{
Attach();
}
}
}
}
void Attach() void Attach()
{ {
if (_mediaPlayer == null)
throw new NullReferenceException(nameof(_mediaPlayer));
_awindow = new AWindow(new SurfaceCallback(_mediaPlayer)); _awindow = new AWindow(new SurfaceCallback(_mediaPlayer));
_awindow.AddCallback(this); _awindow.AddCallback(this);
_awindow.SetVideoView(this); _awindow.SetVideoView(this);
...@@ -51,16 +81,18 @@ namespace LibVLCSharp.Platforms.Android ...@@ -51,16 +81,18 @@ namespace LibVLCSharp.Platforms.Android
void Detach() void Detach()
{ {
_awindow.RemoveCallback(this); _awindow?.RemoveCallback(this);
_awindow.DetachViews(); _awindow?.DetachViews();
_mediaPlayer.SetAndroidContext(IntPtr.Zero); _mediaPlayer?.SetAndroidContext(IntPtr.Zero);
RemoveOnLayoutChangeListener(_layoutListener); if (_layoutListener != null)
_layoutListener.Dispose(); RemoveOnLayoutChangeListener(_layoutListener);
_layoutListener?.Dispose();
_layoutListener = null; _layoutListener = null;
_awindow.Dispose(); _awindow?.Dispose();
_awindow = null; _awindow = null;
} }
...@@ -72,25 +104,15 @@ namespace LibVLCSharp.Platforms.Android ...@@ -72,25 +104,15 @@ namespace LibVLCSharp.Platforms.Android
{ {
} }
void Init(string[] cliOptions) /// <summary>
{ /// Detach the mediaplayer from the view and dispose the view
Core.Initialize(); /// </summary>
/// <param name="disposing"></param>
_libVLC = new LibVLC(cliOptions);
_mediaPlayer = new MediaPlayer(_libVLC);
Attach();
}
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
base.Dispose(disposing); base.Dispose(disposing);
Detach(); Detach();
_mediaPlayer.Media?.Dispose();
_mediaPlayer.Dispose();
_libVLC.Dispose();
} }
} }
} }
\ No newline at end of file
...@@ -6,30 +6,54 @@ namespace LibVLCSharp.Platforms.Mac ...@@ -6,30 +6,54 @@ namespace LibVLCSharp.Platforms.Mac
{ {
public class VideoView : NSView, IVideoView public class VideoView : NSView, IVideoView
{ {
public VideoView(string[] cliOptions = default(string[])) Shared.MediaPlayer _mediaPlayer;
{
LibVLC = new LibVLC(cliOptions);
MediaPlayer = new Shared.MediaPlayer(LibVLC);
Attach(); /// <summary>
/// The MediaPlayer object attached to this VideoView. Use this to manage playback and more
/// </summary>
public Shared.MediaPlayer MediaPlayer
{
get => _mediaPlayer;
set
{
if (_mediaPlayer != value)
{
Detach();
_mediaPlayer = value;
if (_mediaPlayer != null)
{
Attach();
}
}
}
} }
public Shared.MediaPlayer MediaPlayer { get; } void Attach()
public LibVLC LibVLC { get; } {
if (MediaPlayer != null)
void Attach() => MediaPlayer.NsObject = Handle; {
MediaPlayer.NsObject = Handle;
}
}
void Detach() => MediaPlayer.NsObject = IntPtr.Zero; void Detach()
{
if (MediaPlayer != null)
{
MediaPlayer.NsObject = IntPtr.Zero;
}
}
/// <summary>
/// Detach the mediaplayer from the view and dispose the view
/// </summary>
/// <param name="disposing"></param>
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
base.Dispose(disposing); base.Dispose(disposing);
Detach(); Detach();
MediaPlayer.Media?.Dispose();
MediaPlayer.Dispose();
LibVLC.Dispose();
} }
} }
} }
\ No newline at end of file
...@@ -8,30 +8,54 @@ namespace LibVLCSharp.Platforms.iOS ...@@ -8,30 +8,54 @@ namespace LibVLCSharp.Platforms.iOS
{ {
public class VideoView : UIView, IVideoView public class VideoView : UIView, IVideoView
{ {
public VideoView(string[] cliOptions = default(string[])) Shared.MediaPlayer _mediaPlayer;
/// <summary>
/// The MediaPlayer object attached to this VideoView. Use this to manage playback and more
/// </summary>
public Shared.MediaPlayer MediaPlayer
{ {
LibVLC = new LibVLC(cliOptions); get => _mediaPlayer;
MediaPlayer = new Shared.MediaPlayer(LibVLC); set
{
Attach(); if (_mediaPlayer != value)
{
Detach();
_mediaPlayer = value;
if (_mediaPlayer != null)
{
Attach();
}
}
}
} }
public Shared.MediaPlayer MediaPlayer { get; } void Attach()
public LibVLC LibVLC { get; } {
if (MediaPlayer != null)
void Attach() => MediaPlayer.NsObject = Handle; {
MediaPlayer.NsObject = Handle;
}
}
void Detach() => MediaPlayer.NsObject = IntPtr.Zero; void Detach()
{
if (MediaPlayer != null)
{
MediaPlayer.NsObject = IntPtr.Zero;
}
}
/// <summary>
/// Detach the mediaplayer from the view and dispose the view
/// </summary>
/// <param name="disposing"></param>
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
base.Dispose(disposing); base.Dispose(disposing);
Detach(); Detach();
MediaPlayer.Media?.Dispose();
MediaPlayer.Dispose();
LibVLC.Dispose();
} }
} }
} }
\ No newline at end of file
...@@ -3,6 +3,5 @@ ...@@ -3,6 +3,5 @@
public interface IVideoView public interface IVideoView
{ {
MediaPlayer MediaPlayer { get; } MediaPlayer MediaPlayer { get; }
LibVLC LibVLC { get; }
} }
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment