Skip to content

Commit

Permalink
Merge pull request #240 from aiviet/develop
Browse files Browse the repository at this point in the history
Fixed #238 and #239
  • Loading branch information
martijn00 authored Aug 14, 2017
2 parents 42d27a6 + ebaa226 commit f935ba5
Show file tree
Hide file tree
Showing 21 changed files with 263 additions and 56 deletions.
5 changes: 5 additions & 0 deletions MediaManager.Abstractions/IVideoPlayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ public interface IVideoPlayer : IPlaybackManager
/// </summary>
IVideoSurface RenderSurface { get; set; }

/// <summary>
/// True when RenderSurface has been initialized and ready for rendering
/// </summary>
bool IsReadyRendering { get; }

/// <summary>
/// The aspect mode of the video
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions MediaManager.Abstractions/IVideoSurface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
/// </summary>
public interface IVideoSurface
{
bool IsDisposed { get; }
}
}
35 changes: 32 additions & 3 deletions MediaManager.Abstractions/Implementations/MediaManagerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ public async Task Play(IMediaFile mediaFile = null)
if (!MediaQueue.Contains(mediaFile))
MediaQueue.Add(mediaFile);

MediaQueue.SetTrackAsCurrent(mediaFile);
MediaQueue.SetTrackAsCurrent(mediaFile);

await RaiseMediaFileFailedEventOnException(async () =>
{
Expand Down Expand Up @@ -385,9 +385,38 @@ private void RemoveEventHandlers()
_currentPlaybackManager.StatusChanged -= OnStatusChanged;
}

public virtual void Dispose()
#region IDisposable
// Flag: Has Dispose already been called?
bool disposed = false;

// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (disposed)
return;

if (disposing)
{
// Free any other managed objects here.
RemoveEventHandlers();
}

// Free any unmanaged objects here.
//
disposed = true;
}

~MediaManagerBase()
{
RemoveEventHandlers();
Dispose(false);
}
#endregion
}
}
1 change: 0 additions & 1 deletion MediaManager.Android/Audio/AudioPlayerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
using Plugin.MediaManager.Abstractions;
using Plugin.MediaManager.Abstractions.Enums;
using Plugin.MediaManager.Abstractions.EventArguments;
using Plugin.MediaManager.Abstractions.Implementations;
using Plugin.MediaManager.MediaSession;

namespace Plugin.MediaManager
Expand Down
76 changes: 48 additions & 28 deletions MediaManager.Android/Video/VideoPlayerImplementation.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Android.App;
using Android.Content.Res;
using Android.Media;
using Android.OS;
using Android.Runtime;
Expand All @@ -13,7 +10,6 @@
using Plugin.MediaManager.Abstractions;
using Plugin.MediaManager.Abstractions.Enums;
using Plugin.MediaManager.Abstractions.EventArguments;
using Plugin.MediaManager.Abstractions.Implementations;

namespace Plugin.MediaManager
{
Expand All @@ -30,9 +26,9 @@ public VideoPlayerImplementation()
StatusChanged += (sender, args) => OnPlayingHandler(args);
}

private bool isPlayerReady = false;
private bool isPlayerReady = false;

private IScheduledExecutorService _executorService = Executors.NewSingleThreadScheduledExecutor();
private IScheduledExecutorService _executorService = Executors.NewSingleThreadScheduledExecutor();
private IScheduledFuture _scheduledFuture;

private void OnPlayingHandler(StatusChangedEventArgs args)
Expand All @@ -45,7 +41,7 @@ private void OnPlayingHandler(StatusChangedEventArgs args)
if (args.Status == MediaPlayerStatus.Stopped || args.Status == MediaPlayerStatus.Failed || args.Status == MediaPlayerStatus.Paused)
CancelPlayingHandler();
}

private void CancelPlayingHandler()
{
_scheduledFuture?.Cancel(false);
Expand All @@ -56,14 +52,17 @@ private void StartPlayingHandler()
var handler = new Handler();
var runnable = new Runnable(() => { handler.Post(OnPlaying); });
if (!_executorService.IsShutdown)
{
_scheduledFuture = _executorService.ScheduleAtFixedRate(runnable, 100, 1000, TimeUnit.Milliseconds);
{
_scheduledFuture = _executorService.ScheduleAtFixedRate(runnable, 100, 1000, TimeUnit.Milliseconds);
}
}

private void OnPlaying()
{
var progress = (Position.TotalSeconds / Duration.TotalSeconds);
if (!IsReadyRendering)
CancelPlayingHandler(); //RenderSurface is no longer valid => Cancel the periodic firing

var progress = (Position.TotalSeconds / Duration.TotalSeconds);
var position = Position;
var duration = Duration;

Expand All @@ -73,6 +72,13 @@ private void OnPlaying()
duration.TotalSeconds >= 0 ? duration : TimeSpan.Zero));
}

/// <summary>
/// True when RenderSurface has been initialized and ready for rendering
/// </summary>
public bool IsReadyRendering => RenderSurface != null && !RenderSurface.IsDisposed;

VideoView VideoViewCanvas => RenderSurface as VideoView;

private IVideoSurface _renderSurface;
public IVideoSurface RenderSurface {
get {
Expand All @@ -82,8 +88,14 @@ public IVideoSurface RenderSurface {
if (!(value is VideoSurface))
throw new ArgumentException("Not a valid video surface");

var canvas = (VideoSurface)value;
if (_renderSurface == value)
return;

var canvas = (VideoSurface)value;
_renderSurface = canvas;

//New canvas object => need initialization
isPlayerReady = false;
}
}

Expand All @@ -97,9 +109,7 @@ public VideoAspectMode AspectMode {
//TODO: Wrap videoplayer to respect aspectmode
_aspectMode = value;
}
}

VideoView VideoViewCanvas => RenderSurface as VideoView;
}

public IMediaFile CurrentFile { get; set; }
private Android.Net.Uri currentUri { get; set; }
Expand Down Expand Up @@ -150,13 +160,14 @@ protected virtual void OnMediaFileFailed(MediaFileFailedEventArgs e)
{
MediaFileFailed?.Invoke(this, e);
}

public TimeSpan Buffered => IsReadyRendering == false ? TimeSpan.Zero : TimeSpan.FromSeconds(VideoViewCanvas.BufferPercentage);

public TimeSpan Buffered => VideoViewCanvas == null ? TimeSpan.Zero : TimeSpan.FromSeconds(VideoViewCanvas.BufferPercentage);
public TimeSpan Duration => IsReadyRendering == false ? TimeSpan.Zero : TimeSpan.FromSeconds(VideoViewCanvas.Duration);

public TimeSpan Position => IsReadyRendering == false ? TimeSpan.Zero : TimeSpan.FromSeconds(VideoViewCanvas.CurrentPosition);

public TimeSpan Duration => VideoViewCanvas == null ? TimeSpan.Zero : TimeSpan.FromSeconds(VideoViewCanvas.Duration);

public TimeSpan Position => VideoViewCanvas == null ? TimeSpan.Zero : TimeSpan.FromSeconds(VideoViewCanvas.CurrentPosition);
private int lastPosition = 0;
private int lastPosition = 0;

private MediaPlayerStatus _status = MediaPlayerStatus.Stopped;
public MediaPlayerStatus Status
Expand Down Expand Up @@ -187,17 +198,18 @@ public void Init()
mediaController.SetAnchorView(VideoViewCanvas);
VideoViewCanvas.SetMediaController(mediaController);
}

VideoViewCanvas.SetOnCompletionListener(this);
VideoViewCanvas.SetOnErrorListener(this);
VideoViewCanvas.SetOnPreparedListener(this);
VideoViewCanvas.SetOnInfoListener(this);
}

public async Task Play(IMediaFile mediaFile = null)
{
if (VideoViewCanvas == null)
throw new System.Exception("No canvas set for video to play in");
{
if (!IsReadyRendering)
//Android ViewRenderer might not initialize Control yet
return;

if (isPlayerReady == false)
{
Expand Down Expand Up @@ -256,28 +268,36 @@ public async Task Stop()

public void OnCompletion(MediaPlayer mp)
{
Console.WriteLine($"OnCompletion");

OnMediaFinished(new MediaFinishedEventArgs(CurrentFile));
}

public bool OnError(MediaPlayer mp, MediaError what, int extra)
{
Stop().Wait();
Console.WriteLine($"OnError: {what}");

Stop().Wait();
Status = MediaPlayerStatus.Failed;
OnMediaFailed(new MediaFailedEventArgs(what.ToString(), new System.Exception()));
return true;
}

public void OnPrepared(MediaPlayer mp)
{
if(Status == MediaPlayerStatus.Buffering)
Console.WriteLine($"OnPrepared: {Status}");

if (Status == MediaPlayerStatus.Buffering)
VideoViewCanvas.Start();

Status = MediaPlayerStatus.Playing;
}

public bool OnInfo(MediaPlayer mp, [GeneratedEnum] MediaInfo what, int extra)
{
switch (what)
Console.WriteLine($"OnInfo: {what}");

switch (what)
{
case MediaInfo.BadInterleaving:
break;
Expand All @@ -302,6 +322,6 @@ public bool OnInfo(MediaPlayer mp, [GeneratedEnum] MediaInfo what, int extra)
}

return true;
}
}
}
}
11 changes: 11 additions & 0 deletions MediaManager.Android/Video/VideoSurface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,16 @@ protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
base.OnMeasure(widthMeasureSpec, heightMeasureSpec);
}

#region IDisposable
public bool IsDisposed { get; private set; }

protected override void Dispose(bool disposing)
{
IsDisposed = true;

base.Dispose(disposing);
}
#endregion
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using Plugin.MediaManager.Forms;
using Plugin.MediaManager.Forms.Android;
using Xamarin.Forms;
Expand All @@ -11,7 +11,7 @@ public class VideoViewRenderer : ViewRenderer<VideoView, VideoSurface>
{
private VideoSurface _videoSurface;

public static async void Init()
public static void Init()
{
var temp = DateTime.Now;
}
Expand All @@ -24,7 +24,7 @@ protected override void OnElementChanged(ElementChangedEventArgs<VideoView> e)
_videoSurface = new VideoSurface(Context);
SetNativeControl(_videoSurface);
CrossMediaManager.Current.VideoPlayer.RenderSurface = _videoSurface;
}
}
}

protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
Expand Down
7 changes: 4 additions & 3 deletions MediaManager.Forms/MediaManager.Forms/VideoView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,16 @@ private static void OnAspectModeChanged(BindableObject bindable, object oldvalue
{
CrossMediaManager.Current.VideoPlayer.AspectMode = ((VideoAspectMode) newvalue);
}

private static void OnSourceChanged(BindableObject bindable, object oldvalue, object newvalue)
{
{
var video = new MediaFile
{
Url = (string)newvalue,
Type = MediaFileType.Video
};


//Auto play by adding video to the queue and then play
CrossMediaManager.Current.Play(video);
}
}
Expand Down
10 changes: 10 additions & 0 deletions MediaManager.MacOS/VideoSurface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,15 @@ namespace Plugin.MediaManager
{
public class VideoSurface : NSView, IVideoSurface
{
#region IDisposable
public bool IsDisposed { get; private set; }

protected override void Dispose(bool disposing)
{
IsDisposed = true;

base.Dispose(disposing);
}
#endregion
}
}
21 changes: 18 additions & 3 deletions MediaManager.UWP/MediaManagerImplementation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,25 @@ public override IVideoPlayer VideoPlayer

public override IVolumeManager VolumeManager { get; set; } = new VolumeManagerImplementation();

public override void Dispose()
#region IDisposable
bool disposed = false;
protected override void Dispose(bool disposing)
{
base.Dispose();
_mediaButtonPlaybackController.UnsubscribeFromNotifications();
if (disposed)
return;

if (disposing)
{
// Free any other managed objects here.
_mediaButtonPlaybackController.UnsubscribeFromNotifications();
}

base.Dispose(disposing);

// Free any unmanaged objects here.
//
disposed = true;
}
#endregion
}
}
5 changes: 5 additions & 0 deletions MediaManager.UWP/VideoPlayerImplementation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,11 @@ public Task Stop()
return Task.CompletedTask;
}

/// <summary>
/// True when RenderSurface has been initialized and ready for rendering
/// </summary>
public bool IsReadyRendering => RenderSurface != null && !RenderSurface.IsDisposed;

public IVideoSurface RenderSurface
{
get { return _renderSurface; }
Expand Down
Loading

0 comments on commit f935ba5

Please sign in to comment.