1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
6 * Moonlight List (moonlight-list@lists.ximian.com)
8 * Copyright 2007 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
13 #ifndef __MOON_MEDIAELEMENT_H__
14 #define __MOON_MEDIAELEMENT_H__
17 #include <gdk/gdkpixbuf.h>
20 #include "frameworkelement.h"
22 #include "downloader.h"
26 /* @Namespace=System.Windows.Controls */
27 class MediaElement
: public FrameworkElement
{
28 friend class MediaElementPropertyValueProvider
;
32 List
*streamed_markers_queue
; // Thread-safe: Accesses to this field needs to use the mutex.
33 TimelineMarkerCollection
*streamed_markers
; // Main thread only.
34 ErrorEventArgs
*error_args
; // Thread-safe: Accesses to this field needs to use the mutex.
35 MediaMarkerFoundClosure
*marker_closure
;
36 cairo_matrix_t matrix
;
38 PlaylistRoot
*playlist
;
41 guint32 marker_timeout
;
42 // When checking if a marker has been reached, we need to
43 // know the last time the check was made, to see if
44 // the marker's pts hit the region.
45 guint64 previous_position
;
46 // When the position is changed by the client, we store the requested position
47 // here and do the actual seeking async. Note that we might get several seek requests
48 // before the actual seek is done, currently we just seek to the last position requested,
49 // the previous requests are ignored. -1 denotes that there are no pending seeks.
50 TimeSpan seek_to_position
;
51 // This is the last seeked to position. Used to never ever return a Position below this value.
52 guint64 seeked_to_position
;
53 // This is the position when Pause is called. Since the actually Pause is done async, we must report
54 // this value as the current Position.
55 guint64 paused_position
;
57 // Buffering can be caused by:
58 // [1] When the media is opened, we automatically buffer an amount equal to BufferingTime.
59 // - In this case we ask the pipeline how much it has buffered.
61 // [2] When during playback we realize that we don't have enough data.
62 // - In this case we ask the pipelien how much it has buffered.
64 // [3] When we seek, and realize that we don't have enough data.
65 // - In this case the buffering progress is calculated as:
66 // ("last available pts" - "last played pts") / ("seeked to pts" - "last played pts" + BufferingTime)
68 guint64 last_played_pts
;
69 guint64 first_pts
; // the first pts, starts off at GUINT_MAX
70 int buffering_mode
; // if we're in [3] or not: 0 = unknown, 1 = [1], etc.
72 // this is used to know what to do after a Buffering state finishes
73 MediaState prev_state
;
75 // The current state of the media element.
80 void Reinitialize (); // not thread-safe
82 void SetMarkerTimeout (bool start
); // not thread-safe
83 static gboolean
MarkerTimeout (gpointer context
); // not thread-safe
85 // Media event handlers
87 EVENTHANDLER (MediaElement
, Opening
, PlaylistRoot
, EventArgs
); // Not thread-safe
88 EVENTHANDLER (MediaElement
, OpenCompleted
, PlaylistRoot
, EventArgs
); // Not thread-safe
89 EVENTHANDLER (MediaElement
, Seeking
, PlaylistRoot
, EventArgs
); // Not thread-safe
90 EVENTHANDLER (MediaElement
, SeekCompleted
, PlaylistRoot
, EventArgs
); // Not thread-safe
91 EVENTHANDLER (MediaElement
, Seek
, PlaylistRoot
, EventArgs
); // Not thread-safe
92 EVENTHANDLER (MediaElement
, CurrentStateChanged
, PlaylistRoot
, EventArgs
); // Not thread-safe
93 EVENTHANDLER (MediaElement
, MediaError
, PlaylistRoot
, ErrorEventArgs
); // Not thread-safe
94 EVENTHANDLER (MediaElement
, MediaEnded
, PlaylistRoot
, EventArgs
); // Not thread-safe
95 EVENTHANDLER (MediaElement
, DownloadProgressChanged
, PlaylistRoot
, EventArgs
); // Not thread-safe
96 EVENTHANDLER (MediaElement
, BufferingProgressChanged
, PlaylistRoot
, EventArgs
); // Not thread-safe
97 EVENTHANDLER (MediaElement
, Play
, PlaylistRoot
, EventArgs
); // Not thread-safe
98 EVENTHANDLER (MediaElement
, Pause
, PlaylistRoot
, EventArgs
); // Not thread-safe
99 EVENTHANDLER (MediaElement
, Stop
, PlaylistRoot
, EventArgs
); // Not thread-safe
100 EVENTHANDLER (MediaElement
, BufferUnderflow
, PlaylistRoot
, EventArgs
); // Not thread-safe
101 EVENTHANDLER (MediaElement
, EntryChanged
, PlaylistRoot
, EventArgs
); // Not thread-safe
103 EVENTHANDLER (MediaElement
, ShuttingDown
, Deployment
, EventArgs
); // Not thread-safe
105 // Fill in information to/from the media, mediaplayer, etc.
106 // Does not change any state
107 void SetProperties (Media
*media
);
109 void EmitMediaEnded ();
110 void EmitStateChangedAsync ();
111 static void EmitStateChanged (EventObject
*obj
);
112 static void ReportErrorOccurredCallback (EventObject
*obj
);
114 void AddStreamedMarker (TimelineMarker
*marker
); // Thread-safe
115 void AddStreamedMarker (MediaMarker
*marker
); // Thread-safe
116 static MediaResult
AddStreamedMarkerCallback (MediaClosure
*closure
); // Thread-safe
117 void CheckMarkers (guint64 from
, guint64 to
, TimelineMarkerCollection
*col
, bool remove
); // Not thread-safe
118 void CheckMarkers (guint64 from
, guint64 to
); // Not thread-safe
119 void CheckMarkers (); // Not thread-safe
120 void ReadMarkers (Media
*media
, IMediaDemuxer
*demuxer
); // Not thread-safe
123 // Private Property Accessors
125 void SetAudioStreamCount (int count
);
127 void SetBufferingProgress (double progress
);
129 void SetCanPause (bool set
);
130 void SetCanSeek (bool set
);
132 void SetNaturalVideoHeight (int height
);
133 void SetNaturalVideoWidth (int width
);
135 void PlayOrStop (); // Not thread-safe. To the right thing if we can pause, if we have to autoplay, etc.
137 void CreatePlaylist ();
138 void SetPlaylist (PlaylistRoot
*playlist
); // Adds/removes event handlers
141 virtual ~MediaElement () {}
144 /* @GenerateCBinding,GeneratePInvoke */
146 virtual void Dispose ();
149 /* @PropertyType=MediaAttributeCollection,ManagedPropertyType=Dictionary<string\,string>,AutoCreateValue,ManagedSetterAccess=Internal,GenerateAccessors,Validator=MediaAttributeCollectionValidator */
150 const static int AttributesProperty
;
151 /* @PropertyType=gint32,DefaultValue=0,ReadOnly,GenerateAccessors */
152 const static int AudioStreamCountProperty
;
153 /* @PropertyType=gint32,Nullable,GenerateAccessors,Validator=AudioStreamIndexValidator */
154 const static int AudioStreamIndexProperty
;
155 /* @PropertyType=bool,DefaultValue=true,GenerateAccessors */
156 const static int AutoPlayProperty
;
157 /* @PropertyType=double,DefaultValue=0.0,GenerateAccessors,Validator=BalanceValidator */
158 const static int BalanceProperty
;
159 /* @PropertyType=double,DefaultValue=0.0,ReadOnly,GenerateAccessors */
160 const static int BufferingProgressProperty
;
161 /* @PropertyType=TimeSpan,GenerateAccessors,Validator=BufferingTimeValidator */
162 const static int BufferingTimeProperty
;
163 /* @PropertyType=bool,DefaultValue=false,ReadOnly,GenerateAccessors */
164 const static int CanPauseProperty
;
165 /* @PropertyType=bool,DefaultValue=false,ReadOnly,GenerateAccessors */
166 const static int CanSeekProperty
;
167 /* @PropertyType=double,ReadOnly,DefaultValue=0.0,GenerateAccessors */
168 const static int DownloadProgressProperty
;
169 /* @PropertyType=MediaState,ReadOnly,ManagedPropertyType=MediaElementState,DefaultValue=MediaStateClosed,GenerateAccessors */
170 const static int CurrentStateProperty
;
171 /* @PropertyType=bool,DefaultValue=false,GenerateAccessors */
172 const static int IsMutedProperty
;
173 /* @PropertyType=TimelineMarkerCollection,AutoCreateValue,ManagedFieldAccess=Internal,ManagedSetterAccess=Internal,GenerateAccessors */
174 const static int MarkersProperty
;
175 /* @PropertyType=Duration,DefaultValue=Duration::FromSeconds (0),ReadOnly,GenerateAccessors */
176 const static int NaturalDurationProperty
;
177 /* @PropertyType=gint32,DefaultValue=0,ReadOnly,GenerateAccessors,Validator=IntGreaterThanZeroValidator */
178 const static int NaturalVideoHeightProperty
;
179 /* @PropertyType=gint32,DefaultValue=0,ReadOnly,GenerateAccessors,Validator=IntGreaterThanZeroValidator */
180 const static int NaturalVideoWidthProperty
;
181 /* @PropertyType=TimeSpan,AlwaysChange,GenerateAccessors */
182 const static int PositionProperty
;
183 /* @PropertyType=Uri,AlwaysChange,ManagedPropertyType=Uri,Nullable,GenerateAccessors */
184 const static int SourceProperty
;
185 /* @PropertyType=Stretch,DefaultValue=StretchUniform,GenerateAccessors */
186 const static int StretchProperty
;
187 /* @PropertyType=double,DefaultValue=0.5,GenerateAccessors,Validator=VolumeValidator */
188 const static int VolumeProperty
;
190 /* @PropertyType=double,DefaultValue=0.0,GenerateAccessors,ReadOnly */
191 const static int DownloadProgressOffsetProperty
;
192 /* @PropertyType=double,DefaultValue=0.0,GenerateAccessors,ReadOnly */
193 const static int DroppedFramesPerSecondProperty
;
194 /* @PropertyType=double,DefaultValue=0.0,GenerateAccessors,ReadOnly */
195 const static int RenderedFramesPerSecondProperty
;
198 /* @DelegateType=RoutedEventHandler */
199 const static int BufferingProgressChangedEvent
;
200 /* @DelegateType=RoutedEventHandler */
201 const static int CurrentStateChangedEvent
;
202 /* @DelegateType=RoutedEventHandler */
203 const static int DownloadProgressChangedEvent
;
204 /* @DelegateType=TimelineMarkerRoutedEventHandler */
205 const static int MarkerReachedEvent
;
206 /* @DelegateType=RoutedEventHandler */
207 const static int MediaEndedEvent
;
208 /* @DelegateType=EventHandler<ExceptionRoutedEventArgs> */
209 const static int MediaFailedEvent
;
210 // MediaOpened is raised when media is ready to play (we've already started playing, or, if AutoPlay is false, paused).
211 /* @DelegateType=RoutedEventHandler */
212 const static int MediaOpenedEvent
;
213 /* @GenerateManagedEvent=false */
214 const static int MediaInvalidatedEvent
;
216 virtual void SetSurface (Surface
*surface
);
218 MediaPlayer
*GetMediaPlayer () { return mplayer
; }
221 virtual void Render (cairo_t
*cr
, Region
*region
, bool path_only
= false);
222 virtual Point
GetTransformOrigin ();
224 virtual Rect
GetCoverageBounds ();
225 virtual Size
ComputeActualSize ();
226 virtual Size
MeasureOverride (Size availableSize
);
227 virtual Size
ArrangeOverride (Size finalSize
);
229 virtual void OnPropertyChanged (PropertyChangedEventArgs
*args
, MoonError
*error
);
231 void MediaInvalidate ();
233 void SetSource (Downloader
*downloader
, const char *PartName
);
234 void SetUriSource (Uri
*uri
); // This is called from OnPropertyChanged
235 /* @GenerateCBinding,GeneratePInvoke,Version=2.0 */
236 void SetStreamSource (ManagedStreamCallbacks
*stream
);
237 /* @GenerateCBinding,GeneratePInvoke */
238 IMediaDemuxer
*SetDemuxerSource (void *context
, CloseDemuxerCallback close_demuxer
, GetDiagnosticAsyncCallback get_diagnostic
, GetFrameAsyncCallback get_sample
, OpenDemuxerAsyncCallback open_demuxer
, SeekAsyncCallback seek
, SwitchMediaStreamAsyncCallback switch_media_stream
);
240 /* @GenerateCBinding,GeneratePInvoke */
241 void Pause (); // Not thread-safe
243 /* @GenerateCBinding,GeneratePInvoke */
244 void Play (); // Not thread-safe
246 /* @GenerateCBinding,GeneratePInvoke */
247 void Stop (); // Not thread-safe
249 void Seek (TimeSpan to
, bool force
); // Not thread-safe.
251 void ReportErrorOccurred (ErrorEventArgs
*args
); // Thread safe
252 /* @GenerateCBinding,GeneratePInvoke */
253 void ReportErrorOccurred (const char *args
); // Thread safe
256 bool IsClosed () { return state
== MediaStateClosed
; }
257 bool IsOpening () { return state
== MediaStateOpening
; }
258 bool IsBuffering () { return state
== MediaStateBuffering
; }
259 bool IsPlaying () { return state
== MediaStatePlaying
; }
260 bool IsPaused () { return state
== MediaStatePaused
; }
261 bool IsStopped () { return state
== MediaStateStopped
; }
263 bool IsMissingCodecs (); // Not thread-safe
265 void SetPlayRequested (); // Not thread-safe
267 static const char *GetStateName (MediaState state
); // Thread-safe
269 MediaState
GetState () { return state
; } // Thread-safe
270 void SetState (MediaState state
); // Thread-safe
272 virtual bool EnableAntiAlias ();
275 // Public Property Accessors
277 void SetAttributes (MediaAttributeCollection
*attrs
);
278 MediaAttributeCollection
*GetAttributes ();
280 int GetAudioStreamCount ();
282 void SetAudioStreamIndex (gint32 index
);
283 void SetAudioStreamIndex (gint32
* index
);
284 gint32
* GetAudioStreamIndex ();
286 void SetAutoPlay (bool set
);
289 void SetBalance (double balance
);
290 double GetBalance ();
292 double GetBufferingProgress ();
294 void SetBufferingTime (TimeSpan time
);
295 TimeSpan
GetBufferingTime ();
300 void SetCurrentState (MediaState state
);
301 MediaState
GetCurrentState ();
303 void SetIsMuted (bool set
);
306 void SetMarkers (TimelineMarkerCollection
*markers
);
307 TimelineMarkerCollection
*GetMarkers ();
309 void SetNaturalDuration (Duration
*duration
);
310 Duration
*GetNaturalDuration ();
312 int GetNaturalVideoHeight ();
313 int GetNaturalVideoWidth ();
315 void SetPosition (TimeSpan position
);
316 TimeSpan
GetPosition ();
318 void SetVolume (double volume
);
321 void SetDownloadProgressOffset (double value
);
322 double GetDownloadProgressOffset ();
324 void SetRenderedFramesPerSecond (double value
);
325 double GetRenderedFramesPerSecond ();
327 void SetDroppedFramesPerSecond (double value
);
328 double GetDroppedFramesPerSecond ();
330 double GetDownloadProgress ();
331 void SetDownloadProgress (double progress
);
333 void SetSource (Uri
*uri
);
334 void SetSource (Uri uri
);
337 void SetStretch (Stretch stretch
);
338 Stretch
GetStretch ();
342 * MediaElementPropertyValueProvider
345 class MediaElementPropertyValueProvider
: public FrameworkElementProvider
{
348 Value
*current_state
;
349 Value
*rendered_frames_per_second
;
350 Value
*dropped_frames_per_second
;
352 Value
*GetPosition ();
353 Value
*GetCurrentState ();
354 Value
*GetRenderedFramesPerSecond ();
355 Value
*GetDroppedFramesPerSecond ();
357 MediaElementPropertyValueProvider (MediaElement
*obj
, PropertyPrecedence precedence
);
358 virtual ~MediaElementPropertyValueProvider ();
359 virtual Value
*GetPropertyValue (DependencyProperty
*property
);
362 #endif /* __MEDIAELEMENT_H__ */