[longomatch] Add an IPlayerController implementation
- From: Andoni Morales Alastruey <amorales src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [longomatch] Add an IPlayerController implementation
- Date: Tue, 31 Mar 2015 17:29:57 +0000 (UTC)
commit 8b52a3b0ec1ec0bef49c6fbc94936c1d3d619126
Author: Andoni Morales Alastruey <ylatuya gmail com>
Date: Fri Mar 20 18:28:49 2015 +0100
Add an IPlayerController implementation
LongoMatch.Core/Interfaces/IPlayerController.cs | 72 ++
LongoMatch.Core/Interfaces/Multimedia/IPlayer.cs | 66 +-
.../Interfaces/Multimedia/IPlayerController.cs | 31 -
LongoMatch.Core/LongoMatch.Core.csproj | 2 +-
LongoMatch.Services/Services/PlayerController.cs | 753 ++++++++++++++++++++
5 files changed, 866 insertions(+), 58 deletions(-)
---
diff --git a/LongoMatch.Core/Interfaces/IPlayerController.cs b/LongoMatch.Core/Interfaces/IPlayerController.cs
new file mode 100644
index 0000000..bd896bb
--- /dev/null
+++ b/LongoMatch.Core/Interfaces/IPlayerController.cs
@@ -0,0 +1,72 @@
+//
+// Copyright (C) 2015 FLUENDO S.A.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+using System;
+using LongoMatch.Core.Store;
+using LongoMatch.Core.Handlers;
+using LongoMatch.Core.Common;
+using System.Collections.Generic;
+using LongoMatch.Core.Store.Playlists;
+using LongoMatch.Core.Interfaces.Multimedia;
+
+
+namespace LongoMatch.Core.Interfaces
+{
+
+ public interface IPlayerController: IPlayback
+ {
+ event TimeChangedHandler TimeChangedEvent;
+ event StateChangeHandler PlaybackStateChangedEvent;
+ event LoadImageHander LoadImageEvent;
+ event PlaybackRateChangedHandler PlaybackRateChangedEvent;
+ event VolumeChangedHandler VolumeChangedEvent;
+ event ElementLoadedHandler ElementLoadedEvent;
+ event ElementUnloadedHandler ElementUnloadedEvent;
+ event PARChangedHandler PARChangedEvent;
+
+ Image CurrentMiniatureFrame { get; }
+
+ Image CurrentFrame { get; }
+
+ Time Step { get; set; }
+
+ bool IgnoreTicks { get; set; }
+
+ object CamerasLayout { get; set; }
+
+ List<int> CamerasVisible { get; set; }
+
+ void Open (MediaFileSet fileSet);
+
+ void FramerateUp ();
+
+ void FramerateDown ();
+
+ void StepForward ();
+
+ void StepBackward ();
+
+ void TogglePlay ();
+
+ void LoadEvent (MediaFileSet file, TimelineEvent play, Time seekTime, bool playing);
+
+ void LoadPlayListEvent (Playlist playlist, IPlaylistElement play);
+
+ void UnloadCurrentEvent ();
+
+ }
+}
\ No newline at end of file
diff --git a/LongoMatch.Core/Interfaces/Multimedia/IPlayer.cs
b/LongoMatch.Core/Interfaces/Multimedia/IPlayer.cs
index 9cac549..45abab1 100644
--- a/LongoMatch.Core/Interfaces/Multimedia/IPlayer.cs
+++ b/LongoMatch.Core/Interfaces/Multimedia/IPlayer.cs
@@ -37,42 +37,56 @@ using System.Collections.Generic;
namespace LongoMatch.Core.Interfaces.Multimedia
{
- public interface IPlayer: IDisposable
+ public interface IPlayback: IDisposable
{
- // Events
- event ErrorHandler Error;
- event EosHandler Eos;
- event StateChangeHandler StateChange;
- event ReadyToSeekHandler ReadyToSeek;
- Time StreamLength {get;}
- Time CurrentTime {get;}
- double Volume {get;set;}
- bool Playing {get;}
- double Rate {set;}
+ Time StreamLength { get; }
+
+ Time CurrentTime { get; }
+
+ double Volume { get; set; }
+
+ bool Playing { get; }
+
+ double Rate { set; }
List<IntPtr> WindowHandles { set; }
+
IntPtr WindowHandle { set; }
+ void Play ();
+
+ void Pause ();
+
+ void Stop ();
+
+ void Close ();
+
+ bool Seek (Time time, bool accurate = false, bool synchronous = false);
+
+ bool SeekToNextFrame ();
+
+ bool SeekToPreviousFrame ();
+
+ void Expose ();
+ }
+
+ public interface IPlayer: IPlayback
+ {
+ // Events
+ event ErrorHandler Error;
+ event EosHandler Eos;
+ event StateChangeHandler StateChange;
+ event ReadyToSeekHandler ReadyToSeek;
+
bool Open (List<string> mrls);
+
bool Open (string mrl);
+
bool Open (MediaFileSet mfs);
+
bool Open (MediaFile mf);
- void Play();
- void Pause();
- void Stop();
- void Close();
- bool Seek (Time time, bool accurate = false, bool synchronous = false);
- bool SeekToNextFrame();
- bool SeekToPreviousFrame();
- Image GetCurrentFrame (int width=-1, int height=-1);
- void Expose ();
- // Functions to add that belonged to IPlayerBin
- // void Open (MediaFileSet fileSet);
- // void Seek (Time time, bool accurate);
- // void FramerateUp();
- // void FramerateDown();
- // void TogglePlay ();
+ Image GetCurrentFrame (int width = -1, int height = -1);
}
}
diff --git a/LongoMatch.Core/LongoMatch.Core.csproj b/LongoMatch.Core/LongoMatch.Core.csproj
index 5057601..397ee1a 100644
--- a/LongoMatch.Core/LongoMatch.Core.csproj
+++ b/LongoMatch.Core/LongoMatch.Core.csproj
@@ -137,7 +137,7 @@
<Compile Include="Interfaces\IStorage.cs" />
<Compile Include="Interfaces\IStorable.cs" />
<Compile Include="Store\Templates\Team.cs" />
- <Compile Include="Interfaces\Multimedia\IPlayerController.cs" />
+ <Compile Include="Interfaces\IPlayerController.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Common\" />
diff --git a/LongoMatch.Services/Services/PlayerController.cs
b/LongoMatch.Services/Services/PlayerController.cs
new file mode 100644
index 0000000..7b82fb4
--- /dev/null
+++ b/LongoMatch.Services/Services/PlayerController.cs
@@ -0,0 +1,753 @@
+//
+// Copyright (C) 2015 Fluendo S.A.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using LongoMatch.Core.Common;
+using LongoMatch.Core.Handlers;
+using LongoMatch.Core.Interfaces;
+using LongoMatch.Core.Interfaces.Multimedia;
+using LongoMatch.Core.Store;
+using LongoMatch.Core.Store.Playlists;
+using LongoMatch.Video.Common;
+using LongoMatch.Video.Utils;
+using Timer = System.Threading.Timer;
+
+namespace LongoMatch.Services.Services
+{
+ public class PlayerController: IPlayerController
+ {
+ public event TimeChangedHandler TimeChangedEvent;
+ public event StateChangeHandler PlaybackStateChangedEvent;
+ public event LoadImageHander LoadImageEvent;
+ public event PlaybackRateChangedHandler PlaybackRateChangedEvent;
+ public event VolumeChangedHandler VolumeChangedEvent;
+ public event ElementLoadedHandler ElementLoadedEvent;
+ public event ElementUnloadedHandler ElementUnloadedEvent;
+ public event PARChangedHandler PARChangedEvent;
+
+ const int TIMEOUT_MS = 20;
+
+ IPlayer player;
+ TimelineEvent loadedEvent;
+ IPlaylistElement loadedPlaylistElement;
+ Playlist loadedPlaylist;
+
+ Time streamLenght, videoTS, imageLoadedTS;
+ bool readyToSeek, stillimageLoaded;
+ MediaFile activeFile;
+ Seeker seeker;
+ Segment loadedSegment;
+ object[] pendingSeek;
+ Timer timer;
+
+ struct Segment
+ {
+ public Time Start;
+ public Time Stop;
+ }
+
+ #region Constructors
+
+ public PlayerController ()
+ {
+ seeker = new Seeker ();
+ seeker.SeekEvent += HandleSeekEvent;
+ loadedSegment.Start = new Time (-1);
+ loadedSegment.Stop = new Time (int.MaxValue);
+ videoTS = new Time (0);
+ imageLoadedTS = new Time (0);
+ streamLenght = new Time (0);
+ Step = new Time (5000);
+ timer = new Timer (HandleTimeout);
+ CreatePlayer ();
+ }
+
+ #endregion
+
+ #region Properties
+
+ public bool IgnoreTicks {
+ get;
+ set;
+ }
+
+ public List<int> CamerasVisible {
+ get;
+ set;
+ }
+
+ public object CamerasLayout {
+ get;
+ set;
+ }
+
+ public List<IntPtr> WindowHandles {
+ set {
+ throw new NotImplementedException ();
+ }
+ }
+
+ public IntPtr WindowHandle {
+ set {
+ throw new NotImplementedException ();
+ }
+ }
+
+ public double Volume {
+ get {
+ return player.Volume;
+ }
+ set {
+ player.Volume = value;
+ }
+ }
+
+ public double Rate {
+ set {
+ player.Rate = value;
+ }
+ }
+
+ public Time CurrentTime {
+ get {
+ return player.CurrentTime;
+ }
+ }
+
+ public Time StreamLength {
+ get {
+ return player.StreamLength;
+ }
+ }
+
+ public Image CurrentMiniatureFrame {
+ get {
+ return player.GetCurrentFrame (Constants.MAX_THUMBNAIL_SIZE,
Constants.MAX_THUMBNAIL_SIZE);
+ }
+ }
+
+ public Image CurrentFrame {
+ get {
+ return player.GetCurrentFrame ();
+ }
+ }
+
+ public bool Playing {
+ get;
+ set;
+ }
+
+ public MediaFileSet MediaFileSet {
+ get;
+ protected set;
+ }
+
+ public bool Opened {
+ get {
+ return MediaFileSet != null;
+ }
+ }
+
+ public Time Step {
+ get;
+ set;
+ }
+
+ #endregion
+
+ #region Private Properties
+
+ IPlayer Player {
+ get;
+ set;
+ }
+
+ #endregion
+
+
+ #region Public methods
+
+ public void Stop ()
+ {
+ Pause ();
+ }
+
+
+ public void Dispose ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ public void Open (MediaFileSet fileSet)
+ {
+ player.Open (fileSet [0].FilePath);
+ }
+
+ public void Play ()
+ {
+ if (StillImageLoaded) {
+ ReconfigureTimeout (TIMEOUT_MS);
+ } else {
+ EmitLoadImage (null);
+ player.Play ();
+ }
+ Playing = true;
+ }
+
+ public void Pause ()
+ {
+ if (StillImageLoaded) {
+ ReconfigureTimeout (0);
+ } else {
+ player.Pause ();
+ }
+ Playing = false;
+ }
+
+ public void Close ()
+ {
+ player.Error -= OnError;
+ player.StateChange -= OnStateChanged;
+ player.Eos -= OnEndOfStream;
+ player.ReadyToSeek -= OnReadyToSeek;
+ ReconfigureTimeout (0);
+ player.Dispose ();
+ MediaFileSet = null;
+ }
+
+ public void TogglePlay ()
+ {
+ if (Playing)
+ Pause ();
+ else
+ Play ();
+ }
+
+ public bool Seek (Time time, bool accurate, bool synchronous = false)
+ {
+ if (!StillImageLoaded) {
+ EmitLoadImage (null);
+ if (readyToSeek) {
+ player.Seek (time + activeFile.Offset, accurate, synchronous);
+ OnTick ();
+ } else {
+ Log.Debug ("Delaying seek until player is ready");
+ pendingSeek = new object[3] { time, 1.0f, false };
+ }
+ }
+ return true;
+ }
+
+ public bool SeekToNextFrame ()
+ {
+ if (!StillImageLoaded) {
+ EmitLoadImage (null);
+ if (CurrentTime < loadedSegment.Stop) {
+ player.SeekToNextFrame ();
+ OnTick ();
+ }
+ }
+ return true;
+ }
+
+ public bool SeekToPreviousFrame ()
+ {
+ if (!StillImageLoaded) {
+ EmitLoadImage (null);
+ if (CurrentTime > loadedSegment.Start) {
+ seeker.Seek (SeekType.StepDown);
+ }
+ }
+ return true;
+ }
+
+ public void StepForward ()
+ {
+ if (StillImageLoaded) {
+ return;
+ }
+ EmitLoadImage (null);
+ DoStep (Step);
+ }
+
+ public void StepBackward ()
+ {
+ if (StillImageLoaded) {
+ return;
+ }
+ EmitLoadImage (null);
+ DoStep (new Time (-Step.MSeconds));
+ }
+
+ public void FramerateUp ()
+ {
+ if (!StillImageLoaded) {
+ EmitLoadImage (null);
+ }
+
+ /* FIXME */
+ //vscale1.Adjustment.Value += vscale1.Adjustment.StepIncrement;
+ }
+
+ public void FramerateDown ()
+ {
+ if (!StillImageLoaded) {
+ EmitLoadImage (null);
+ }
+ /* FIXME */
+ //vscale1.Adjustment.Value -= vscale1.Adjustment.StepIncrement;
+ }
+
+ public void Expose ()
+ {
+ player.Expose ();
+ }
+
+ public void LoadPlayListEvent (Playlist playlist, IPlaylistElement element)
+ {
+ loadedEvent = null;
+ loadedPlaylist = playlist;
+ loadedPlaylistElement = element;
+ EmitElementLoaded (playlist.HasNext ());
+
+ if (element is PlaylistPlayElement) {
+ PlaylistPlayElement ple = element as PlaylistPlayElement;
+ TimelineEvent play = ple.Play;
+ LoadSegment (ple.FileSet, play.Start, play.Stop, play.Start, true, ple.Rate);
+ } else if (element is PlaylistVideo) {
+ LoadVideo (element as PlaylistVideo);
+ } else if (element is PlaylistImage) {
+ LoadStillImage (element as PlaylistImage);
+ } else if (element is PlaylistDrawing) {
+ LoadFrameDrawing (element as PlaylistDrawing);
+ }
+ }
+
+ public void LoadEvent (MediaFileSet fileSet, TimelineEvent evt, Time seekTime, bool playing)
+ {
+ loadedPlaylist = null;
+ loadedPlaylistElement = null;
+ loadedEvent = evt;
+ if (evt.Start != null && evt.Start != null) {
+ LoadSegment (fileSet, evt.Start, evt.Stop, seekTime, playing, evt.Rate);
+ } else if (evt.EventTime != null) {
+ Seek (evt.EventTime, true);
+ } else {
+ Log.Error ("Event does not have timing info: " + evt);
+ }
+ }
+
+ public void UnloadCurrentEvent ()
+ {
+ EmitEventUnloaded ();
+ SetRate (1);
+ StillImageLoaded = false;
+ loadedSegment.Start = new Time (-1);
+ loadedSegment.Stop = new Time (int.MaxValue);
+ loadedEvent = null;
+ }
+
+ #endregion
+
+ #region Signals
+
+ void EmitLoadImage (Image image, FrameDrawing drawing = null, bool isStill = false)
+ {
+ if (LoadImageEvent != null) {
+ LoadImageEvent (image, drawing);
+ }
+ }
+
+ void EmitElementLoaded (bool hasNext)
+ {
+ if (ElementLoadedEvent != null) {
+ ElementLoadedEvent (hasNext);
+ }
+ }
+
+ void EmitEventUnloaded ()
+ {
+ if (ElementUnloadedEvent != null) {
+ ElementUnloadedEvent ();
+ }
+ }
+
+ void EmitRateChanged (float rate)
+ {
+ if (PlaybackRateChangedEvent != null) {
+ PlaybackRateChangedEvent (rate);
+ }
+ }
+
+ void EmitVolumeChanged (float volume)
+ {
+ if (VolumeChangedEvent != null) {
+ VolumeChangedEvent (volume);
+ }
+ }
+
+ void EmitTimeChanged (Time currentTime, Time duration)
+ {
+ if (TimeChangedEvent != null) {
+ TimeChangedEvent (currentTime, duration, StillImageLoaded);
+ }
+ }
+
+ void EmitPARChanged (float par)
+ {
+ if (PARChangedEvent != null) {
+ PARChangedEvent (par);
+ }
+ }
+
+ void EmitPlaybackStateChanged (bool playing)
+ {
+ if (PlaybackStateChangedEvent != null) {
+ PlaybackStateChangedEvent (playing);
+ }
+ }
+
+ #endregion
+
+ #region Private methods
+
+ void SetRate (float rate)
+ {
+ Rate = rate;
+ EmitRateChanged (rate);
+ }
+
+ bool StillImageLoaded {
+ set {
+ stillimageLoaded = value;
+ if (stillimageLoaded) {
+ player.Pause ();
+ imageLoadedTS = new Time (0);
+ ReconfigureTimeout (TIMEOUT_MS);
+ }
+ }
+ get {
+ return stillimageLoaded;
+ }
+ }
+
+ void Open (MediaFileSet fileSet, bool seek, bool force = false, bool play = false)
+ {
+ UnloadCurrentEvent ();
+ if (fileSet != this.MediaFileSet || force) {
+ readyToSeek = false;
+ MediaFileSet = fileSet;
+ activeFile = fileSet.First ();
+ if (activeFile.VideoHeight != 0) {
+ EmitPARChanged ((float)(activeFile.VideoWidth * activeFile.Par /
activeFile.VideoHeight));
+ } else {
+ EmitPARChanged (1);
+ }
+ try {
+ Log.Debug ("Opening new file " + activeFile.FilePath);
+ player.Open (fileSet);
+ } catch (Exception ex) {
+ Log.Exception (ex);
+ //We handle this error async
+ }
+ } else {
+ if (seek) {
+ Seek (new Time (0), true);
+ }
+ }
+ if (play) {
+ player.Play ();
+ }
+ }
+
+ bool SegmentLoaded {
+ get {
+ return loadedSegment.Start.MSeconds != -1;
+ }
+ }
+
+ List<FrameDrawing> EventDrawings {
+ get {
+ if (loadedEvent != null) {
+ return loadedEvent.Drawings;
+ } else if (loadedPlaylistElement is PlaylistPlayElement) {
+ return (loadedPlaylistElement as PlaylistPlayElement).Play.Drawings;
+ }
+ return null;
+ }
+ }
+
+ void LoadSegment (MediaFileSet fileSet, Time start, Time stop, Time seekTime,
+ bool playing, float rate = 1)
+ {
+ Log.Debug (String.Format ("Update player segment {0} {1} {2}",
+ start.ToMSecondsString (),
+ stop.ToMSecondsString (), rate));
+ if (fileSet != this.MediaFileSet) {
+ Open (fileSet, false);
+ }
+ Pause ();
+ loadedSegment.Start = start;
+ loadedSegment.Stop = stop;
+ rate = rate == 0 ? 1 : rate;
+ EmitElementLoaded (false);
+ StillImageLoaded = false;
+ if (readyToSeek) {
+ Log.Debug ("Player is ready to seek, seeking to " +
+ seekTime.ToMSecondsString ());
+ SetRate (rate);
+ Seek (seekTime, true);
+ if (playing) {
+ Play ();
+ }
+ } else {
+ Log.Debug ("Delaying seek until player is ready");
+ pendingSeek = new object[3] { seekTime, rate, playing };
+ }
+ }
+
+ void LoadImage (Image image, FrameDrawing drawing)
+ {
+ EmitLoadImage (image, drawing);
+ }
+
+ void LoadStillImage (PlaylistImage image)
+ {
+ loadedPlaylistElement = image;
+ UnloadCurrentEvent ();
+ StillImageLoaded = true;
+ LoadImage (image.Image, null);
+ }
+
+ void LoadFrameDrawing (PlaylistDrawing drawing)
+ {
+ loadedPlaylistElement = drawing;
+ UnloadCurrentEvent ();
+ StillImageLoaded = true;
+ LoadImage (null, drawing.Drawing);
+ }
+
+ void LoadVideo (PlaylistVideo video)
+ {
+ loadedPlaylistElement = video;
+ MediaFileSet fileSet = new MediaFileSet ();
+ fileSet.Add (video.File);
+ Open (fileSet, false, true, true);
+ }
+
+ void LoadPlayDrawing (FrameDrawing drawing)
+ {
+ Pause ();
+ IgnoreTicks = true;
+ player.Seek (drawing.Render + activeFile.Offset, true, true);
+ IgnoreTicks = false;
+ LoadImage (CurrentFrame, drawing);
+ }
+
+ void DoStep (Time step)
+ {
+ Time pos = CurrentTime + step;
+ if (pos.MSeconds < 0)
+ pos.MSeconds = 0;
+ Log.Debug (String.Format ("Stepping {0} seconds from {1} to {2}",
+ step, CurrentTime, pos));
+ EmitLoadImage (null);
+ Seek (pos, true);
+ }
+
+ void SeekFromTimescale (double pos)
+ {
+ Time seekPos, duration;
+ SeekType seekType;
+
+ if (SegmentLoaded) {
+ duration = loadedSegment.Stop - loadedSegment.Start;
+ seekPos = loadedSegment.Start + duration * pos;
+ seekType = SeekType.Accurate;
+ } else {
+ duration = streamLenght;
+ seekPos = streamLenght * pos;
+ seekType = SeekType.Keyframe;
+ }
+ seeker.Seek (seekType, seekPos);
+ EmitTimeChanged (seekPos, duration);
+ }
+
+ void CreatePlayer ()
+ {
+ player = Config.MultimediaToolkit.GetPlayer ();
+
+ player.Error += OnError;
+ player.StateChange += OnStateChanged;
+ player.Eos += OnEndOfStream;
+ player.ReadyToSeek += OnReadyToSeek;
+ }
+
+ void ReconfigureTimeout (uint mseconds)
+ {
+ if (mseconds == 0) {
+ timer.Change (Timeout.Infinite, Timeout.Infinite);
+ } else {
+ timer.Change (mseconds, mseconds);
+ }
+ }
+
+ void DoStateChanged (bool playing)
+ {
+ if (playing) {
+ ReconfigureTimeout (TIMEOUT_MS);
+ } else {
+ if (!StillImageLoaded) {
+ ReconfigureTimeout (0);
+ }
+ }
+ EmitPlaybackStateChanged (playing);
+ }
+
+ void DoReadyToSeek ()
+ {
+ readyToSeek = true;
+ streamLenght = player.StreamLength;
+ if (pendingSeek != null) {
+ SetRate ((float)pendingSeek [1]);
+ player.Seek ((Time)pendingSeek [0], true);
+ if ((bool)pendingSeek [2]) {
+ Play ();
+ }
+ pendingSeek = null;
+ }
+ OnTick ();
+ }
+
+ #endregion
+
+ #region Backend Callbacks
+
+ /* These callbacks are triggered by the multimedia backend and need to
+ * be deferred to the UI main thread */
+ void OnStateChanged (bool playing)
+ {
+ Config.DrawingToolkit.Invoke (delegate {
+ DoStateChanged (playing);
+ });
+ }
+
+ void OnReadyToSeek ()
+ {
+ Config.DrawingToolkit.Invoke (delegate {
+ DoReadyToSeek ();
+ });
+ }
+
+ void OnEndOfStream ()
+ {
+ Config.DrawingToolkit.Invoke (delegate {
+ if (loadedPlaylistElement is PlaylistVideo) {
+ Config.EventsBroker.EmitNextPlaylistElement (loadedPlaylist);
+ } else {
+ Seek (new Time (0), true);
+ Pause ();
+ }
+ });
+ }
+
+ void OnError (string message)
+ {
+ Config.DrawingToolkit.Invoke (delegate {
+ Config.EventsBroker.EmitMultimediaError (message);
+ });
+ }
+
+ #endregion
+
+ #region Callbacks
+
+ void HandleTimeout (Object state)
+ {
+ OnTick ();
+ }
+
+ bool OnTick ()
+ {
+ if (IgnoreTicks) {
+ return true;
+ }
+
+ if (StillImageLoaded) {
+ EmitTimeChanged (imageLoadedTS, loadedPlaylistElement.Duration);
+ if (imageLoadedTS >= loadedPlaylistElement.Duration) {
+ Config.EventsBroker.EmitNextPlaylistElement (loadedPlaylist);
+ } else {
+ imageLoadedTS.MSeconds += TIMEOUT_MS;
+ }
+ return true;
+ } else {
+ Time currentTime = CurrentTime;
+
+ if (SegmentLoaded) {
+ EmitTimeChanged (currentTime - loadedSegment.Start,
+ loadedSegment.Stop - loadedSegment.Start);
+ if (currentTime > loadedSegment.Stop) {
+ /* Check if the segment is now finished and jump to next one
*/
+ Pause ();
+ Config.EventsBroker.EmitNextPlaylistElement (loadedPlaylist);
+ } else {
+ var drawings = EventDrawings;
+ if (drawings != null) {
+ /* Check if the event has drawings to display */
+ FrameDrawing fd = drawings.FirstOrDefault (f =>
f.Render > videoTS && f.Render <= currentTime);
+ if (fd != null) {
+ LoadPlayDrawing (fd);
+ }
+ }
+ }
+ } else {
+ EmitTimeChanged (currentTime, streamLenght);
+ }
+ videoTS = currentTime;
+
+ Config.EventsBroker.EmitPlayerTick (currentTime);
+ return true;
+ }
+ }
+
+ void HandleSeekEvent (SeekType type, Time start, float rate)
+ {
+ EmitLoadImage (null, null);
+ /* We only use it for backwards framestepping for now */
+ if (type == SeekType.StepDown || type == SeekType.StepUp) {
+ if (player.Playing)
+ Pause ();
+ if (type == SeekType.StepDown)
+ player.SeekToPreviousFrame ();
+ else
+ player.SeekToNextFrame ();
+ OnTick ();
+ }
+ if (type == SeekType.Accurate || type == SeekType.Keyframe) {
+ SetRate (rate);
+ Seek (start, type == SeekType.Accurate);
+ }
+ }
+
+ #endregion
+ }
+}
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]