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.
18 #include "downloader.h"
21 #include "pipeline-asf.h"
22 #include "pipeline-ui.h"
23 #include "mediaelement.h"
25 #include "deployment.h"
26 #include "mediaplayer.h"
28 #include "timemanager.h"
33 class TimelineMarkerNode
: public List::Node
{
35 TimelineMarker
*marker
;
38 TimelineMarkerNode (TimelineMarker
*marker
)
40 this->marker
= marker
;
43 virtual ~TimelineMarkerNode ()
47 TimelineMarker
*GetTimelineMarker () { return marker
; }
54 enum MediaElementFlags
{
55 PlayRequested
= (1 << 2), // set if Play() has been requested prior to being ready
56 BufferingFailed
= (1 << 3), // set if TryOpen failed to buffer the media.
57 DisableBuffering
= (1 << 4), // set if we cannot give useful buffering progress
58 RecalculateMatrix
= (1 << 7), // set if the patern matrix needs to be recomputed
59 MediaOpenedEmitted
= (1 << 9), // set if MediaOpened has been emitted.
60 MissingCodecs
= (1 << 11), // set if we have no video codecs
61 AutoPlayed
= (1 << 12), // set if we've autoplayed
62 UpdatingSizeFromMedia
= (1 << 13),
63 UseMediaHeight
= (1 << 14),
64 UseMediaWidth
= (1 << 15),
71 MediaElement::MediaElement ()
73 SetObjectType (Type::MEDIAELEMENT
);
75 streamed_markers
= NULL
;
76 streamed_markers_queue
= NULL
;
77 marker_closure
= NULL
;
81 flags
= UseMediaWidth
| UseMediaHeight
;
88 providers
[PropertyPrecedence_DynamicValue
] = new MediaElementPropertyValueProvider (this, PropertyPrecedence_DynamicValue
);
90 // Note: BufferingTime and Position need to be set in the ctor
91 // so that ReadLocalValue() will get these values.
92 SetValue (MediaElement::BufferingTimeProperty
, Value (TimeSpan_FromSeconds (5), Type::TIMESPAN
));
93 SetValue (MediaElement::PositionProperty
, Value (TimeSpan_FromSeconds (0), Type::TIMESPAN
));
95 GetDeployment ()->AddHandler (Deployment::ShuttingDownEvent
, ShuttingDownCallback
, this);
99 MediaElement::Dispose ()
101 LOG_MEDIAELEMENT ("MediaElement::Dispose ()\n");
104 GetDeployment ()->RemoveHandler (Deployment::ShuttingDownEvent
, ShuttingDownCallback
, this);
107 FrameworkElement::Dispose ();
111 MediaElement::ShuttingDownHandler (Deployment
*sender
, EventArgs
*args
)
113 LOG_MEDIAELEMENT ("MediaElement::ShuttingDownHandler ()\n");
119 MediaElement::GetStateName (MediaState state
)
121 return enums_int_to_str ("MediaState", state
);
125 MediaElement::AddStreamedMarkerCallback (MediaClosure
*c
)
127 MediaMarkerFoundClosure
*closure
= (MediaMarkerFoundClosure
*) c
;
128 MediaElement
*element
= (MediaElement
*) closure
->GetContext ();
129 MediaMarker
*mmarker
= closure
->GetMarker ();
136 element
->AddStreamedMarker (mmarker
);
138 return MEDIA_SUCCESS
;
142 MediaElement::AddStreamedMarker (MediaMarker
*mmarker
)
145 TimelineMarker
*marker
;
147 g_return_if_fail (mmarker
!= NULL
);
149 pts
= mmarker
->Pts ();
151 marker
= new TimelineMarker ();
152 marker
->SetText (mmarker
->Text ());
153 marker
->SetType (mmarker
->Type ());
154 marker
->SetTime (pts
);
156 AddStreamedMarker (marker
);
161 MediaElement::AddStreamedMarker (TimelineMarker
*marker
)
163 LOG_MEDIAELEMENT ("MediaElement::AddStreamedMarker (): got marker %s, %s, %" G_GUINT64_FORMAT
" = %" G_GUINT64_FORMAT
" ms\n",
164 marker
->GetText (), marker
->GetType (), marker
->GetTime (),
165 MilliSeconds_FromPts (marker
->GetTime ()));
170 if (streamed_markers_queue
== NULL
)
171 streamed_markers_queue
= new List ();
172 streamed_markers_queue
->Append (new TimelineMarkerNode (marker
));
177 MediaElement::ReadMarkers (Media
*media
, IMediaDemuxer
*demuxer
)
179 LOG_MEDIAELEMENT ("MediaElement::ReadMarkers ()\n");
182 g_return_if_fail (demuxer
!= NULL
);
183 g_return_if_fail (media
!= NULL
);
185 for (int i
= 0; i
< demuxer
->GetStreamCount (); i
++) {
186 if (demuxer
->GetStream (i
)->GetType () == MediaTypeMarker
) {
187 MarkerStream
*stream
= (MarkerStream
*) demuxer
->GetStream (i
);
189 if (marker_closure
== NULL
)
190 marker_closure
= new MediaMarkerFoundClosure (media
, AddStreamedMarkerCallback
, this);
192 stream
->SetCallback (marker_closure
);
194 MediaMarker
*m
= stream
->Pop ();
196 AddStreamedMarker (m
);
204 TimelineMarkerCollection
*markers
= NULL
;
205 MediaMarker::Node
*current
= (MediaMarker::Node
*) media
->GetMarkers ()->First ();
207 if (current
== NULL
) {
208 //printf ("MediaElement::ReadMarkers (): no markers.\n");
212 markers
= new TimelineMarkerCollection ();
213 while (current
!= NULL
) {
214 TimelineMarker
*new_marker
= new TimelineMarker ();
215 MediaMarker
*marker
= current
->marker
;
217 new_marker
->SetText (marker
->Text ());
218 new_marker
->SetType (marker
->Type ());
219 new_marker
->SetTime (TimeSpan_FromPts (marker
->Pts ()));
224 new_marker
->unref ();
226 current
= (MediaMarker::Node
*) current
->next
;
229 // Docs says we overwrite whatever's been loaded already.
230 LOG_MEDIAELEMENT ("MediaElement::ReadMarkers (): setting %d markers.\n", markers
->GetCount ());
231 SetMarkers (markers
);
236 MediaElement::MarkerTimeout (gpointer context
)
239 ((MediaElement
*) context
)->SetCurrentDeployment ();
240 ((MediaElement
*) context
)->CheckMarkers ();
245 MediaElement::SetMarkerTimeout (bool start
)
252 surface
= GetDeployment ()->GetSurface ();
257 tm
= surface
->GetTimeManager ();
259 g_return_if_fail (tm
!= NULL
);
262 if (marker_timeout
== 0) {
263 marker_timeout
= tm
->AddTimeout (MOON_PRIORITY_DEFAULT
, 33, MarkerTimeout
, this);
266 if (marker_timeout
!= 0) {
267 tm
->RemoveTimeout (marker_timeout
);
274 MediaElement::CheckMarkers ()
276 guint64 current_position
= GetPosition ();
278 LOG_MARKERS_EX ("MediaElement::CheckMarkers () current position: %" G_GUINT64_FORMAT
", previous position: %" G_GUINT64_FORMAT
")\n", current_position
, previous_position
);
281 if (current_position
> previous_position
&& seek_to_position
== -1) {
282 guint64 tmp
= previous_position
;
283 // We need to set previous_position before calling CheckMarkers,
284 // as CheckMarkers may end up emitting events, causing seeks
285 // which will change previous_position.
286 previous_position
= current_position
;
287 CheckMarkers (tmp
, current_position
- 1);
292 MediaElement::CheckMarkers (guint64 from
, guint64 to
)
294 TimelineMarkerCollection
*markers
;
296 LOG_MARKERS_EX ("MediaElement::CheckMarkers (%" G_GUINT64_FORMAT
", %" G_GUINT64_FORMAT
")\n", from
, to
);
300 LOG_MARKERS ("MediaElement::CheckMarkers (%" G_GUINT64_FORMAT
", %" G_GUINT64_FORMAT
"). from == to\n", from
, to
);
304 if (!(markers
= GetMarkers ())) {
305 LOG_MARKERS ("MediaElement::CheckMarkers (%" G_GUINT64_FORMAT
", %" G_GUINT64_FORMAT
"). No markers\n", from
, to
);
310 // if from > to we've seeked backwards (last played position is after this one)
311 LOG_MARKERS ("MediaElement::CheckMarkers (%" G_GUINT64_FORMAT
", %" G_GUINT64_FORMAT
"). from > to (diff: %" G_GUINT64_FORMAT
" = %" G_GUINT64_FORMAT
" ms).\n", from
, to
, from
- to
, MilliSeconds_FromPts (from
- to
));
315 /* Check if we've got streamed markers */
317 if (streamed_markers_queue
!= NULL
) {
318 TimelineMarkerNode
*node
= (TimelineMarkerNode
*) streamed_markers_queue
->First ();
319 while (node
!= NULL
) {
320 if (streamed_markers
== NULL
)
321 streamed_markers
= new TimelineMarkerCollection ();
322 streamed_markers
->Add (node
->GetTimelineMarker ());
323 node
= (TimelineMarkerNode
*) node
->next
;
325 streamed_markers_queue
->Clear (true);
329 CheckMarkers (from
, to
, markers
, false);
330 CheckMarkers (from
, to
, streamed_markers
, true);
334 MediaElement::CheckMarkers (guint64 from
, guint64 to
, TimelineMarkerCollection
*markers
, bool remove
)
336 TimelineMarker
*marker
;
342 LOG_MARKERS ("MediaElement::CheckMarkers (%" G_GUINT64_FORMAT
", %" G_GUINT64_FORMAT
", %p, %i). count: %i\n", from
, to
, markers
, remove
, markers
? markers
->GetCount () : -1);
345 // We might want to use a more intelligent algorithm here,
346 // this code only loops through all markers on every frame.
348 if (markers
!= NULL
) {
349 for (int i
= 0; i
< markers
->GetCount (); i
++) {
350 marker
= markers
->GetValueAt (i
)->AsTimelineMarker ();
352 if (!(val
= marker
->GetValue (TimelineMarker::TimeProperty
)))
355 pts
= (guint64
) val
->AsTimeSpan ();
357 LOG_MARKERS_EX ("MediaElement::CheckMarkers (%" G_GUINT64_FORMAT
", %" G_GUINT64_FORMAT
"): Checking pts: %" G_GUINT64_FORMAT
", enqueued %i elements\n", from
, to
, pts
, emit_list
.GetCount ());
361 // Streamed markers. Emit these even if we passed them with up to 1 s.
362 if (from
<= MilliSeconds_ToPts (1000)) {
363 emit
= pts
>= 0 && pts
<= to
;
365 emit
= pts
>= (from
- MilliSeconds_ToPts (1000)) && pts
<= to
;
368 LOG_MARKERS_EX ("MediaElement::CheckMarkers (%" G_GUINT64_FORMAT
", %" G_GUINT64_FORMAT
"): emit: %i, Checking pts: %" G_GUINT64_FORMAT
" in marker with Text = %s, Type = %s (removed from from)\n",
369 from
<= MilliSeconds_ToPts (1000) ? 0 : from
- MilliSeconds_ToPts (1000), to
, emit
, pts
, marker
->GetText (), marker
->GetType ());
372 emit
= pts
>= from
&& pts
<= to
;
373 LOG_MARKERS_EX ("MediaElement::CheckMarkers (%" G_GUINT64_FORMAT
", %" G_GUINT64_FORMAT
"): Checking pts: %" G_GUINT64_FORMAT
" in marker with Text = %s, Type = %s\n",
374 from
, to
, pts
, marker
->GetText (), marker
->GetType ());
379 emit_list
.Add (marker
);
381 LOG_MARKERS ("MediaElement::CheckMarkers (%" G_GUINT64_FORMAT
", %" G_GUINT64_FORMAT
"): Emitting: Text = %s, Type = %s, Time = %" G_GUINT64_FORMAT
" = %" G_GUINT64_FORMAT
" ms, count: %in",
382 from
, to
, marker
->GetText (), marker
->GetType (), marker
->GetTime (), MilliSeconds_FromPts (marker
->GetTime ()), emit_list
.GetCount ());
385 if (remove
&& (pts
<= to
|| emit
)) {
386 // Also delete markers we've passed by already
387 markers
->RemoveAt (i
);
393 for (int i
= 0; i
< emit_list
.GetCount (); i
++) {
394 marker
= (TimelineMarker
*) emit_list
[i
];
395 Emit (MarkerReachedEvent
, new MarkerReachedEventArgs (marker
));
401 MediaElement::SetSurface (Surface
*s
)
405 if (GetSurface() == s
)
409 mplayer
->SetSurface (s
);
412 LOG_PIPELINE ("MediaElement::SetSurface (%p): Stopping media element since we're detached.\n", s
);
414 mplayer
->Stop (); /* this is immediate */
415 Stop (); /* this is async */
418 if (!SetSurfaceLock ())
420 FrameworkElement::SetSurface (s
);
425 MediaElement::Reinitialize ()
427 TimelineMarkerCollection
*markers
;
428 MediaAttributeCollection
*attrs
;
430 LOG_MEDIAELEMENT ("MediaElement::Reinitialize ()\n");
439 if (marker_closure
) {
440 marker_closure
->Dispose ();
441 marker_closure
->unref ();
442 marker_closure
= NULL
;
445 if (playlist
!= NULL
) {
446 playlist
->Dispose ();
451 flags
&= (PlayRequested
| UseMediaHeight
| UseMediaWidth
);
452 flags
|= RecalculateMatrix
;
454 prev_state
= MediaStateClosed
;
455 state
= MediaStateClosed
;
458 first_pts
= G_MAXUINT64
;
459 seek_to_position
= -1;
460 seeked_to_position
= 0;
465 delete streamed_markers_queue
;
466 streamed_markers_queue
= NULL
;
467 if (streamed_markers
) {
468 streamed_markers
->unref ();
469 streamed_markers
= NULL
;
472 error_args
->unref ();
477 previous_position
= 0;
479 SetMarkerTimeout (false);
480 if ((markers
= GetMarkers ()))
483 if ((attrs
= GetAttributes ()))
486 cairo_matrix_init_identity (&matrix
);
490 MediaElement::IsMissingCodecs ()
493 return flags
& MissingCodecs
;
497 MediaElement::GetTransformOrigin ()
499 Point
*user_xform_origin
= GetRenderTransformOrigin ();
500 double h
= GetActualHeight();
501 double w
= GetActualWidth ();
503 if (w
== 0.0 && h
== 0.0 && mplayer
!= NULL
) {
504 h
= (double) mplayer
->GetVideoHeight ();
505 w
= (double) mplayer
->GetVideoWidth ();
508 return Point (user_xform_origin
->x
* w
, user_xform_origin
->y
* h
);
512 MediaElement::ComputeActualSize ()
514 Size result
= FrameworkElement::ComputeActualSize ();
515 Size specified
= Size (GetWidth (), GetHeight ());
518 Size available
= Size (INFINITY
, INFINITY
);
519 available
= available
.Min (specified
);
520 result
= MeasureOverride (available
);
523 //g_warning ("actual is %g,%g", result.width, result.height);
529 MediaElement::MeasureOverride (Size availableSize
)
531 Size desired
= availableSize
;
532 Rect shape_bounds
= Rect ();
537 shape_bounds
= Rect (0,0,
538 mplayer
->GetVideoWidth (),
539 mplayer
->GetVideoHeight ());
541 if (GetStretch () == StretchNone
)
542 return desired
.Min (shape_bounds
.width
, shape_bounds
.height
);
544 /* don't stretch to infinite size */
545 if (isinf (desired
.width
))
546 desired
.width
= shape_bounds
.width
;
547 if (isinf (desired
.height
))
548 desired
.height
= shape_bounds
.height
;
550 /* compute the scaling */
551 if (shape_bounds
.width
> 0)
552 sx
= desired
.width
/ shape_bounds
.width
;
553 if (shape_bounds
.height
> 0)
554 sy
= desired
.height
/ shape_bounds
.height
;
556 switch (GetStretch ()) {
558 sx
= sy
= MIN (sx
, sy
);
560 case StretchUniformToFill
:
561 sx
= sy
= MAX (sx
, sy
);
567 desired
= desired
.Min (shape_bounds
.width
* sx
, shape_bounds
.height
* sy
);
573 MediaElement::ArrangeOverride (Size finalSize
)
575 Size arranged
= finalSize
;
576 Rect shape_bounds
= Rect ();
581 shape_bounds
= Rect (0, 0,
582 mplayer
->GetVideoWidth (),
583 mplayer
->GetVideoHeight ());
585 if (GetStretch () == StretchNone
) {
586 arranged
= Size (shape_bounds
.x
+ shape_bounds
.width
,
587 shape_bounds
.y
+ shape_bounds
.height
);
589 if (GetHorizontalAlignment () == HorizontalAlignmentStretch
)
590 arranged
.width
= MAX (arranged
.width
, finalSize
.width
);
592 if (GetVerticalAlignment () == VerticalAlignmentStretch
)
593 arranged
.height
= MAX (arranged
.height
, finalSize
.height
);
599 /* compute the scaling */
600 if (shape_bounds
.width
== 0)
601 shape_bounds
.width
= arranged
.width
;
602 if (shape_bounds
.height
== 0)
603 shape_bounds
.height
= arranged
.height
;
605 if (shape_bounds
.width
!= arranged
.width
)
606 sx
= arranged
.width
/ shape_bounds
.width
;
607 if (shape_bounds
.height
!= arranged
.height
)
608 sy
= arranged
.height
/ shape_bounds
.height
;
610 switch (GetStretch ()) {
612 sx
= sy
= MIN (sx
, sy
);
614 case StretchUniformToFill
:
615 sx
= sy
= MAX (sx
, sy
);
621 arranged
= Size (shape_bounds
.width
* sx
, shape_bounds
.height
* sy
);
627 MediaElement::GetCoverageBounds ()
629 MediaPlayer
*mplayer
= GetMediaPlayer ();
630 Stretch stretch
= GetStretch ();
632 if (IsClosed () || !mplayer
|| !mplayer
->HasRenderedFrame ())
635 if (stretch
== StretchFill
|| stretch
== StretchUniformToFill
)
638 Rect video
= Rect (0, 0, mplayer
->GetVideoWidth (), mplayer
->GetVideoHeight ());
639 cairo_matrix_t brush_xform
= matrix
;
641 cairo_matrix_invert (&brush_xform
);
642 cairo_matrix_multiply (&brush_xform
, &brush_xform
, &absolute_xform
);
644 video
= video
.Transform (&brush_xform
);
645 video
= video
.Intersection (bounds
);
651 MediaElement::Render (cairo_t
*cr
, Region
*region
, bool path_only
)
653 Stretch stretch
= GetStretch ();
654 cairo_surface_t
*surface
;
655 cairo_pattern_t
*pattern
;
657 if (!mplayer
|| !(surface
= mplayer
->GetCairoSurface ()))
661 cairo_set_matrix (cr
, &absolute_xform
);
664 Size
framework (GetActualWidth (), GetActualHeight ());
665 Rect
video (0, 0, mplayer
->GetVideoWidth (), mplayer
->GetVideoHeight ());
667 if (stretch
!= StretchNone
)
668 framework
= ApplySizeConstraints (framework
);
670 Rect
paint (0, 0, framework
.width
, framework
.height
);
673 if (absolute_xform.xy == 0 && absolute_xform.yx == 0) {
674 //cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
675 cairo_matrix_t inv = absolute_xform;
676 cairo_matrix_invert (&inv);
677 paint = paint.Transform (&absolute_xform);
678 paint = paint.RoundIn ();
679 paint = paint.Transform (&inv);
683 image_brush_compute_pattern_matrix (&matrix
,
684 paint
.width
, paint
.height
,
685 video
.width
, video
.height
,
686 stretch
, AlignmentXCenter
,
687 AlignmentYCenter
, NULL
, NULL
);
689 pattern
= cairo_pattern_create_for_surface (surface
);
691 cairo_pattern_set_matrix (pattern
, &matrix
);
693 cairo_set_source (cr
, pattern
);
694 cairo_pattern_destroy (pattern
);
697 cairo_pattern_set_filter (cairo_get_source (cr
), CAIRO_FILTER_FAST
);
700 RenderLayoutClip (cr
);
711 MediaElement::BufferUnderflowHandler (PlaylistRoot
*sender
, EventArgs
*args
)
713 LOG_MEDIAELEMENT ("MediaElement::BufferUnderflow (): Switching to 'Buffering', previous_position: %" G_GUINT64_FORMAT
" ms, mplayer->GetPosition (): %" G_GUINT64_FORMAT
" ms\n",
714 MilliSeconds_FromPts (previous_position
), MilliSeconds_FromPts (mplayer
->GetPosition ()));
716 flags
|= PlayRequested
;
717 SetBufferingProgress (0.0);
718 Emit (BufferingProgressChangedEvent
);
719 SetState (MediaStateBuffering
);
724 MediaElement::EmitStateChangedAsync ()
726 AddTickCallSafe (EmitStateChanged
);
730 MediaElement::EmitStateChanged (EventObject
*obj
)
732 ((MediaElement
*) obj
)->Emit (CurrentStateChangedEvent
);
736 MediaElement::SetState (MediaState state
)
740 LOG_MEDIAELEMENT ("MediaElement::SetState (%d): New state: %s, old state: %s\n",
741 state
, GetStateName (state
), GetStateName (this->state
));
746 if (this->state
!= state
) {
747 prev_state
= this->state
;
753 if (emit
) // Don't emit with mutex locked.
754 EmitStateChangedAsync ();
758 MediaElement::CreatePlaylist ()
760 g_return_if_fail (mplayer
== NULL
);
762 mplayer
= new MediaPlayer (this);
763 SetPlaylist (new PlaylistRoot (this));
767 MediaElement::SetPlaylist (PlaylistRoot
*value
)
769 // if playlist is something, then value must be null (and vice versa)
770 g_return_if_fail ((playlist
== NULL
) != (value
== NULL
));
774 if (playlist
!= NULL
) {
775 playlist
->RemoveAllHandlers (this);
776 playlist
->Dispose ();
780 playlist
= value
; // We assume the caller gives us a reference to the playlist
781 playlist
->AddHandler (PlaylistRoot::OpeningEvent
, OpeningCallback
, this);
782 playlist
->AddHandler (PlaylistRoot::OpenCompletedEvent
, OpenCompletedCallback
, this);
783 playlist
->AddHandler (PlaylistRoot::SeekingEvent
, SeekingCallback
, this);
784 playlist
->AddHandler (PlaylistRoot::SeekCompletedEvent
, SeekCompletedCallback
, this);
785 playlist
->AddHandler (PlaylistRoot::CurrentStateChangedEvent
, CurrentStateChangedCallback
, this);
786 playlist
->AddHandler (PlaylistRoot::MediaErrorEvent
, MediaErrorCallback
, this);
787 playlist
->AddHandler (PlaylistRoot::MediaEndedEvent
, MediaEndedCallback
, this);
788 playlist
->AddHandler (PlaylistRoot::BufferUnderflowEvent
, BufferUnderflowCallback
, this);
789 playlist
->AddHandler (PlaylistRoot::DownloadProgressChangedEvent
, DownloadProgressChangedCallback
, this);
790 playlist
->AddHandler (PlaylistRoot::BufferingProgressChangedEvent
, BufferingProgressChangedCallback
, this);
791 playlist
->AddHandler (PlaylistRoot::PlayEvent
, PlayCallback
, this);
792 playlist
->AddHandler (PlaylistRoot::PauseEvent
, PauseCallback
, this);
793 playlist
->AddHandler (PlaylistRoot::StopEvent
, StopCallback
, this);
794 playlist
->AddHandler (PlaylistRoot::EntryChangedEvent
, EntryChangedCallback
, this);
799 MediaElement::EntryChangedHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
801 LOG_MEDIAELEMENT ("MediaElement::EntryChangedHandler ()\n");
802 flags
&= ~MediaOpenedEmitted
;
806 MediaElement::OpeningHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
808 LOG_MEDIAELEMENT ("MediaElement::OpeningHandler ()\n");
811 SetState (MediaStateOpening
);
815 MediaElement::OpenCompletedHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
817 IMediaDemuxer
*demuxer
;
818 const char *demuxer_name
;
819 PlaylistEntry
*entry
;
824 g_return_if_fail (playlist
!= NULL
);
825 g_return_if_fail (mplayer
!= NULL
);
827 entry
= playlist
->GetCurrentPlaylistEntry ();
829 g_return_if_fail (entry
!= NULL
);
831 media
= entry
->GetMedia ();
833 g_return_if_fail (media
!= NULL
);
835 demuxer
= media
->GetDemuxer ();
836 demuxer_name
= demuxer
->GetName ();
838 LOG_MEDIAELEMENT ("MediaElement::OpenCompletedHandler (%p), demuxer name: %s\n", media
, demuxer_name
);
840 // Try to figure out if we're missing codecs
841 for (int i
= 0; i
< demuxer
->GetStreamCount (); i
++) {
842 IMediaStream
*stream
= demuxer
->GetStream (i
);
843 IMediaDecoder
*decoder
= stream
->GetDecoder ();
844 const char *decoder_name
= decoder
? decoder
->GetName () : NULL
;
845 if (decoder_name
!= NULL
&& strcmp (decoder_name
, "NullDecoder") == 0) {
846 flags
|= MissingCodecs
;
851 // check if we're missing the codecs *and* if they are not installed
852 // since we could already have downloaded/installed them without refreshing the browser (leading to a crash)
853 if ((flags
& MissingCodecs
) && !Media::IsMSCodecsInstalled ())
854 CodecDownloader::ShowUI (GetDeployment ()->GetSurface ());
856 entry
->PopulateMediaAttributes ();
857 SetProperties (media
);
859 if (!(flags
& MediaOpenedEmitted
)) {
860 flags
|= MediaOpenedEmitted
;
864 // This is a workaround for MS DRT #78: it tests that download progress has changed
865 // from the latest DownloadProgressChanged event to the MediaOpened event (unless
866 // DownloadProgress is 0.0 or 1.0).
867 double progress
= media
->GetDownloadProgress ();
868 progress
= MAX (progress
, GetDownloadProgress ());
869 progress
= MIN (progress
+ 0.00000001, 1.0);
870 SetDownloadProgress (progress
);
871 Emit (MediaOpenedEvent
, new RoutedEventArgs ());
872 Emit (DownloadProgressChangedEvent
);
877 MediaElement::SetProperties (Media
*media
)
879 IMediaDemuxer
*demuxer
;
880 PlaylistEntry
*entry
;
881 Duration
*natural_duration
;
882 bool can_seek
= true;
883 bool can_pause
= true;
885 LOG_MEDIAELEMENT ("MediaElement::SetProperties (%p)\n", media
);
887 g_return_if_fail (media
!= NULL
);
888 g_return_if_fail (playlist
!= NULL
);
890 seeked_to_position
= 0;
892 demuxer
= media
->GetDemuxer ();
893 entry
= playlist
->GetCurrentPlaylistEntry ();
895 g_return_if_fail (demuxer
!= NULL
);
896 g_return_if_fail (entry
!= NULL
);
898 ReadMarkers (media
, demuxer
);
901 if (entry
->GetIsLive ()) {
905 can_seek
= entry
->GetClientSkip () && demuxer
->GetCanSeek ();
909 natural_duration
= new Duration (TimeSpan_FromPts (mplayer
->GetDuration ()));
910 SetCanPause (can_pause
);
911 SetCanSeek (can_seek
);
912 SetNaturalDuration (natural_duration
);
913 SetNaturalVideoHeight ((double) mplayer
->GetVideoHeight ());
914 SetNaturalVideoWidth ((double) mplayer
->GetVideoWidth ());
915 SetAudioStreamCount (mplayer
->GetAudioStreamCount ());
917 mplayer
->SetMuted (GetIsMuted ());
918 mplayer
->SetVolume (GetVolume ());
921 InvalidateMeasure ();
922 InvalidateArrange ();
926 MediaElement::SeekingHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
928 LOG_MEDIAELEMENT ("MediaElement::SeekingHandler ()\n");
931 SetMarkerTimeout (false);
935 MediaElement::SeekCompletedHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
937 LOG_MEDIAELEMENT ("MediaElement::SeekCompletedHandler ()\n");
940 if (state
== MediaStatePlaying
)
941 playlist
->PlayAsync ();
943 seek_to_position
= -1;
944 SetMarkerTimeout (true);
948 MediaElement::PlayHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
950 LOG_MEDIAELEMENT ("MediaElement::PlayHandler ()\n");
953 SetMarkerTimeout (true);
955 SetState (MediaStatePlaying
);
959 MediaElement::PauseHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
961 LOG_MEDIAELEMENT ("MediaElement::PauseHandler ()\n");
964 SetMarkerTimeout (false);
966 SetState (MediaStatePaused
);
970 MediaElement::StopHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
972 PlaylistEntry
*entry
;
974 LOG_MEDIAELEMENT ("MediaElement::StopHandler ()\n");
977 g_return_if_fail (playlist
!= NULL
);
979 entry
= playlist
->GetCurrentPlaylistEntry ();
981 g_return_if_fail (entry
!= NULL
);
982 seeked_to_position
= 0;
984 SetProperties (entry
->GetMedia ());
986 SetMarkerTimeout (false);
987 CheckMarkers (); // check one last time.
989 SetState (MediaStateStopped
);
993 MediaElement::CurrentStateChangedHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
995 LOG_MEDIAELEMENT ("MediaElement::CurrentStateChangedHandler ()\n");
1000 MediaElement::MediaErrorHandler (PlaylistRoot
*playlist
, ErrorEventArgs
*args
)
1002 LOG_MEDIAELEMENT ("MediaElement::MediaErrorHandler (). State: %s Message: %s\n", GetStateName (state
), args
? args
->GetErrorMessage() : NULL
);
1005 if (state
== MediaStateClosed
)
1008 // TODO: Should ClearValue be called on these instead?
1009 SetAudioStreamCount (0);
1010 SetNaturalVideoHeight (0);
1011 SetNaturalVideoWidth (0);
1012 SetNaturalDuration (0);
1013 SetCanPause (false);
1015 SetDownloadProgress (0);
1016 SetDownloadProgressOffset (0);
1017 SetRenderedFramesPerSecond (0);
1018 SetDroppedFramesPerSecond (0);
1021 InvalidateMeasure ();
1022 InvalidateArrange ();
1024 SetState (MediaStateClosed
);
1028 Emit (MediaFailedEvent
, args
);
1032 MediaElement::MediaEndedHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
1034 LOG_MEDIAELEMENT ("MediaElement::MediaEndedHandler ()\n");
1038 paused_position
= GetPosition ();
1039 SetState (MediaStatePaused
);
1040 Emit (MediaEndedEvent
);
1044 MediaElement::DownloadProgressChangedHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
1046 ProgressEventArgs
*pea
= (ProgressEventArgs
*) args
;
1048 LOG_MEDIAELEMENT ("MediaElement::DownloadProgressChangedHandler (): %f\n", pea
? pea
->progress
: -1.0);
1051 g_return_if_fail (pea
!= NULL
);
1053 SetDownloadProgress (pea
->progress
);
1054 Emit (DownloadProgressChangedEvent
);
1058 MediaElement::BufferingProgressChangedHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
1060 ProgressEventArgs
*pea
= (ProgressEventArgs
*) args
;
1062 LOG_MEDIAELEMENT ("MediaElement::BufferingProgressChangedHandler (): %f\n", pea
? pea
->progress
: -1.0);
1065 g_return_if_fail (pea
!= NULL
);
1067 if (GetBufferingProgress () < pea
->progress
) {
1068 SetBufferingProgress (pea
->progress
);
1069 Emit (BufferingProgressChangedEvent
);
1072 if (pea
->progress
>= 1.0 && GetState () == MediaStateBuffering
) {
1073 LOG_MEDIAELEMENT ("MediaElement::BufferingProgressChangedHandler (): buffer full, playing...\n");
1079 MediaElement::MediaInvalidate ()
1081 Emit (MediaInvalidatedEvent
);
1086 MediaElement::SetUriSource (Uri
*uri
)
1088 LOG_MEDIAELEMENT ("MediaElement::SetUriSource ('%s')\n", uri
? uri
->ToString () : NULL
);
1093 g_return_if_fail (playlist
== NULL
);
1095 if (uri
!= NULL
&& uri
->originalString
!= NULL
&& uri
->originalString
[0] != 0) {
1097 char *str
= uri
->ToString ();
1098 playlist
->GetCurrentEntry ()->InitializeWithUri (str
);
1102 InvalidateMeasure ();
1103 InvalidateArrange ();
1108 MediaElement::SetSource (Downloader
*downloader
, const char *PartName
)
1110 LOG_MEDIAELEMENT ("MediaElement::SetSource (%p, '%s')\n", downloader
, PartName
);
1115 g_return_if_fail (downloader
!= NULL
);
1116 g_return_if_fail (playlist
== NULL
);
1119 playlist
->GetCurrentEntry ()->InitializeWithDownloader (downloader
, PartName
);
1123 MediaElement::SetStreamSource (ManagedStreamCallbacks
*callbacks
)
1125 LOG_MEDIAELEMENT ("MediaElement::SetStreamSource (%p)\n", callbacks
);
1130 g_return_if_fail (callbacks
!= NULL
);
1131 g_return_if_fail (playlist
== NULL
);
1134 playlist
->GetCurrentEntry ()->InitializeWithStream (callbacks
);
1136 SetDownloadProgress (1.0);
1140 MediaElement::SetDemuxerSource (void *context
, CloseDemuxerCallback close_demuxer
, GetDiagnosticAsyncCallback get_diagnostic
, GetFrameAsyncCallback get_sample
,
1141 OpenDemuxerAsyncCallback open_demuxer
, SeekAsyncCallback seek
, SwitchMediaStreamAsyncCallback switch_media_stream
)
1143 ExternalDemuxer
*demuxer
;
1146 LOG_MEDIAELEMENT ("MediaElement::SetDemuxerSource (%p)\n", demuxer
);
1151 g_return_val_if_fail (context
!= NULL
, NULL
);
1152 g_return_val_if_fail (close_demuxer
!= NULL
&& get_diagnostic
!= NULL
&& get_sample
!= NULL
&& open_demuxer
!= NULL
&& seek
!= NULL
&& switch_media_stream
!= NULL
, NULL
);
1153 g_return_val_if_fail (playlist
== NULL
, NULL
);
1156 media
= new Media (playlist
);
1157 demuxer
= new ExternalDemuxer (media
, context
, close_demuxer
, get_diagnostic
, get_sample
, open_demuxer
, seek
, switch_media_stream
);
1158 playlist
->GetCurrentEntry ()->InitializeWithDemuxer (demuxer
);
1161 SetDownloadProgress (1.0);
1167 MediaElement::SetPlayRequested ()
1169 LOG_MEDIAELEMENT ("MediaElement::SetPlayRequested ()\n");
1172 flags
|= PlayRequested
;
1176 MediaElement::PlayOrStop ()
1178 LOG_MEDIAELEMENT ("MediaElement::PlayOrPause (): GetCanPause (): %s, PlayRequested: %s, GetAutoPlay: %s, AutoPlayed: %s\n",
1179 GetCanPause () ? "true" : "false", (flags
& PlayRequested
) ? "true" : "false",
1180 GetAutoPlay () ? "true" : "false", (flags
& AutoPlayed
) ? "true" : "false");
1183 if (!GetCanPause ()) {
1184 // If we can't pause, we play
1185 SetState (MediaStatePlaying
);
1186 playlist
->PlayAsync ();
1187 } else if (flags
& PlayRequested
) {
1188 // A Play has already been requested.
1189 SetState (MediaStatePlaying
);
1190 playlist
->PlayAsync ();
1191 } else if (GetAutoPlay () && !(flags
& AutoPlayed
)) {
1193 flags
|= AutoPlayed
;
1194 SetState (MediaStatePlaying
);
1195 playlist
->PlayAsync ();
1197 SetState (MediaStatePaused
);
1202 MediaElement::Pause ()
1204 LOG_MEDIAELEMENT ("MediaElement::Pause (): current state: %s\n", GetStateName (state
));
1207 g_return_if_fail (playlist
!= NULL
);
1210 case MediaStateOpening
:// docs: No specified behaviour
1211 flags
&= ~PlayRequested
;
1213 case MediaStateClosed
: // docs: No specified behaviour
1215 case MediaStatePaused
:// docs: no-op
1216 case MediaStateBuffering
:
1217 case MediaStatePlaying
:
1218 case MediaStateStopped
: // docs: pause
1219 paused_position
= GetPosition ();
1220 SetState (MediaStatePaused
);
1221 playlist
->PauseAsync ();
1223 case MediaStateIndividualizing
:
1224 case MediaStateAcquiringLicense
:
1225 g_warning ("MediaElement: Invalid state.");
1231 MediaElement::Play ()
1233 LOG_MEDIAELEMENT ("MediaElement::Play (): current state: %s\n", GetStateName (state
));
1236 g_return_if_fail (playlist
!= NULL
);
1239 case MediaStateClosed
: // docs: No specified behaviour
1240 case MediaStateOpening
:// docs: No specified behaviour
1241 flags
|= PlayRequested
;
1243 case MediaStatePlaying
:// docs: no-op
1244 case MediaStateBuffering
:
1245 case MediaStatePaused
:
1246 case MediaStateStopped
:
1247 SetState (MediaStatePlaying
);
1248 playlist
->PlayAsync ();
1250 case MediaStateIndividualizing
:
1251 case MediaStateAcquiringLicense
:
1252 g_warning ("MediaElement: Invalid state.");
1258 MediaElement::Stop ()
1260 LOG_MEDIAELEMENT ("MediaElement::Stop (): current state: %s\n", GetStateName (state
));
1263 if (GetSurface () == NULL
)
1267 case MediaStateOpening
:// docs: No specified behaviour
1268 flags
&= ~PlayRequested
;
1270 case MediaStateClosed
: // docs: No specified behaviour
1271 case MediaStateStopped
:// docs: no-op
1273 case MediaStateBuffering
:
1274 case MediaStatePlaying
:
1275 case MediaStatePaused
: // docs: stop
1276 flags
&= ~PlayRequested
;
1278 LOG_MEDIAELEMENT ("MediaElement::Stop (): state: %s, IsSingleFile: %i\n", GetStateName (state
), playlist
->IsSingleFile ());
1280 if (!playlist
->IsSingleFile ())
1281 flags
&= ~MediaOpenedEmitted
; // for playlists we must re-emit MediaOpened when the first entry/media has been re-loaded (even though we stop the first entry).
1283 SetState (MediaStateStopped
);
1284 playlist
->StopAsync ();
1286 case MediaStateIndividualizing
:
1287 case MediaStateAcquiringLicense
:
1288 g_warning ("MediaElement: Invalid state.");
1294 MediaElement::Seek (TimeSpan to
, bool force
)
1296 LOG_MEDIAELEMENT ("MediaElement::Seek (%" G_GUINT64_FORMAT
" = %" G_GUINT64_FORMAT
" ms)\n", to
, MilliSeconds_FromPts (to
));
1299 if (GetSurface () == NULL
)
1302 if (!force
&& !GetCanSeek ()) {
1303 LOG_MEDIAELEMENT ("MediaElement::Seek (): CanSeek is false, not seeking\n");
1308 case MediaStateIndividualizing
:
1309 case MediaStateAcquiringLicense
:
1310 g_warning ("MediaElement:Seek (): Invalid state %s\n", GetStateName (state
));
1312 case MediaStateOpening
:
1313 case MediaStateClosed
:
1317 case MediaStateBuffering
:
1318 case MediaStatePlaying
:
1319 case MediaStatePaused
:
1320 case MediaStateStopped
:
1321 Duration
*duration
= GetNaturalDuration ();
1323 if (duration
->HasTimeSpan () && to
> duration
->GetTimeSpan ())
1324 to
= duration
->GetTimeSpan ();
1328 if (!force
&& to
== TimeSpan_FromPts (mplayer
->GetPosition ()))
1331 previous_position
= to
;
1332 seek_to_position
= to
;
1333 seeked_to_position
= to
;
1334 paused_position
= to
;
1336 mplayer
->NotifySeek (TimeSpan_ToPts (to
));
1337 playlist
->SeekAsync (to
);
1338 Emit (MediaInvalidatedEvent
);
1341 LOG_MEDIAELEMENT ("MediaElement::Seek (%" G_GUINT64_FORMAT
" = %" G_GUINT64_FORMAT
" ms) previous position: %" G_GUINT64_FORMAT
"\n", to
, MilliSeconds_FromPts (to
), previous_position
);
1348 MediaElement::OnPropertyChanged (PropertyChangedEventArgs
*args
, MoonError
*error
)
1350 if (args
->GetId () == MediaElement::SourceProperty
) {
1351 DownloaderAccessPolicy policy
= MediaPolicy
;
1352 Uri
*uri
= GetSource ();
1353 const char *location
;
1356 if (!(location
= GetDeployment ()->GetXapLocation ()) && GetSurface ())
1357 location
= GetSurface ()->GetSourceLocation ();
1359 if (uri
->scheme
&& (!strcmp (uri
->scheme
, "mms") || !strcmp (uri
->scheme
, "rtsp") || !strcmp (uri
->scheme
, "rtsps")))
1360 policy
= StreamingPolicy
;
1362 if (uri
->IsInvalidPath ()) {
1363 EmitAsync (MediaFailedEvent
, new ErrorEventArgs (MediaError
, MoonError (MoonError::ARGUMENT_OUT_OF_RANGE
, 0, "invalid path found in uri")));
1365 } else if (!Downloader::ValidateDownloadPolicy (location
, uri
, policy
)) {
1366 EmitAsync (MediaFailedEvent
, new ErrorEventArgs (MediaError
, MoonError (MoonError::ARGUMENT_OUT_OF_RANGE
, 0, "Security Policy Violation")));
1371 flags
|= RecalculateMatrix
;
1373 } else if (args
->GetId () == MediaElement::AudioStreamIndexProperty
) {
1375 mplayer
->SetAudioStreamIndex (args
->GetNewValue()->AsInt32 ());
1376 } else if (args
->GetId () == MediaElement::AutoPlayProperty
) {
1377 // no state to change
1378 } else if (args
->GetId () == MediaElement::BalanceProperty
) {
1380 mplayer
->SetBalance (args
->GetNewValue()->AsDouble ());
1381 } else if (args
->GetId () == MediaElement::BufferingProgressProperty
) {
1382 // read-only property
1383 } else if (args
->GetId () == MediaElement::BufferingTimeProperty
) {
1385 // Not quite sure what to do here, we could:
1386 // a) store the buffering time on the mediaplayer and let the media request it whenever it needs it
1387 // b) let the media request the buffering time from mediaelement
1388 // c) always keep the current media up to date (this is harder to do right when we get multiple media downloading at the same time)
1389 // note that thread-safety is easier with a) (media will do the request from another thread) or c)
1392 media->SetBufferingTime (TimeSpan_ToPts (GetBufferingTime ()));
1394 } else if (args
->GetId () == MediaElement::CurrentStateProperty
) {
1395 // read-only property
1396 // This should really not happen, we use a property provider for this property.
1397 } else if (args
->GetId () == MediaElement::IsMutedProperty
) {
1399 mplayer
->SetMuted (args
->GetNewValue()->AsBool ());
1400 } else if (args
->GetId () == MediaElement::MarkersProperty
) {
1402 } else if (args
->GetId () == MediaElement::NaturalVideoHeightProperty
) {
1403 // read-only property
1404 flags
|= RecalculateMatrix
;
1405 } else if (args
->GetId () == MediaElement::NaturalVideoWidthProperty
) {
1406 // read-only property
1407 flags
|= RecalculateMatrix
;
1408 } else if (args
->GetId () == MediaElement::PositionProperty
) {
1409 Seek (args
->GetNewValue()->AsTimeSpan (), false);
1410 ClearValue (MediaElement::PositionProperty
, false); // We need this, otherwise our property system will return the seeked-to position forever (MediaElementPropertyValueProvider isn't called).
1411 } else if (args
->GetId () == MediaElement::VolumeProperty
) {
1413 mplayer
->SetVolume (args
->GetNewValue()->AsDouble ());
1416 if (args
->GetProperty ()->GetOwnerType() != Type::MEDIAELEMENT
) {
1417 // propagate to parent class
1418 FrameworkElement::OnPropertyChanged (args
, error
);
1419 flags
|= RecalculateMatrix
;
1423 NotifyListenersOfPropertyChange (args
, error
);
1427 MediaElement::EnableAntiAlias (void)
1429 return !(absolute_xform
.xx
== absolute_xform
.yy
&& /* no rotation */
1430 (absolute_xform
.yx
== 0 && absolute_xform
.xy
== 0)); /* no skew */
1435 MediaElement::ReportErrorOccurredCallback (EventObject
*obj
)
1437 MediaElement
*me
= (MediaElement
*) obj
;
1438 ErrorEventArgs
*args
;
1441 args
= me
->error_args
;
1442 me
->error_args
= NULL
;
1443 me
->mutex
.Unlock ();
1445 me
->ReportErrorOccurred (args
);
1451 MediaElement::ReportErrorOccurred (ErrorEventArgs
*args
)
1453 LOG_MEDIAELEMENT ("MediaElement::ReportErrorOccurred (%p)\n", args
);
1455 if (!Surface::InMainThread ()) {
1458 error_args
->unref ();
1463 AddTickCallSafe (ReportErrorOccurredCallback
);
1468 MediaErrorHandler (NULL
, args
);
1472 MediaElement::ReportErrorOccurred (const char *args
)
1474 LOG_MEDIAELEMENT ("MediaElement::ReportErrorOccurred ('%s')\n", args
);
1476 ErrorEventArgs
*eea
= new ErrorEventArgs (MediaError
, MoonError (MoonError::EXCEPTION
, 3001, g_strdup (args
)));
1477 ReportErrorOccurred (eea
);
1482 * MediaElementPropertyValueProvider
1485 MediaElementPropertyValueProvider::MediaElementPropertyValueProvider (MediaElement
*element
, PropertyPrecedence precedence
)
1486 : FrameworkElementProvider (element
, precedence
)
1489 current_state
= NULL
;
1490 rendered_frames_per_second
= NULL
;
1491 dropped_frames_per_second
= NULL
;
1494 MediaElementPropertyValueProvider::~MediaElementPropertyValueProvider ()
1497 delete current_state
;
1498 delete rendered_frames_per_second
;
1499 delete dropped_frames_per_second
;
1503 MediaElementPropertyValueProvider::GetPropertyValue (DependencyProperty
*property
)
1505 // We verify main thread here too in case some object in the pipeline happens to want a property on the media element
1508 if (property
->GetId () == MediaElement::PositionProperty
)
1509 return GetPosition ();
1511 if (property
->GetId () == MediaElement::CurrentStateProperty
)
1512 return GetCurrentState ();
1514 if (property
->GetId () == MediaElement::DroppedFramesPerSecondProperty
)
1515 return GetDroppedFramesPerSecond ();
1517 if (property
->GetId () == MediaElement::RenderedFramesPerSecondProperty
)
1518 return GetRenderedFramesPerSecond ();
1520 return FrameworkElementProvider::GetPropertyValue (property
);
1524 MediaElementPropertyValueProvider::GetDroppedFramesPerSecond ()
1526 MediaElement
*element
= (MediaElement
*) obj
;
1527 MediaPlayer
*mplayer
= element
->GetMediaPlayer ();
1529 delete dropped_frames_per_second
;
1532 dropped_frames_per_second
= new Value (mplayer
->GetDroppedFramesPerSecond ());
1534 dropped_frames_per_second
= NULL
;
1537 return dropped_frames_per_second
;
1541 MediaElementPropertyValueProvider::GetRenderedFramesPerSecond ()
1543 MediaElement
*element
= (MediaElement
*) obj
;
1544 MediaPlayer
*mplayer
= element
->GetMediaPlayer ();
1546 delete rendered_frames_per_second
;
1549 rendered_frames_per_second
= new Value (mplayer
->GetRenderedFramesPerSecond ());
1551 rendered_frames_per_second
= NULL
;
1554 return rendered_frames_per_second
;
1558 MediaElementPropertyValueProvider::GetCurrentState ()
1560 MediaElement
*element
= (MediaElement
*) obj
;
1562 delete current_state
;
1563 current_state
= new Value (element
->state
);
1565 return current_state
;
1569 MediaElementPropertyValueProvider::GetPosition ()
1571 bool use_mplayer
= false;;
1572 bool use_pause
= false;
1573 MediaElement
*element
= (MediaElement
*) obj
;
1574 guint64 position
= TimeSpan_ToPts (element
->seek_to_position
);
1576 delete this->position
;
1577 this->position
= NULL
;
1579 switch (element
->state
) {
1580 case MediaStateIndividualizing
:
1581 case MediaStateAcquiringLicense
:
1582 g_warning ("MediaElementPropertyValueProvider::GetPosition (): Invalid state.\n");
1584 case MediaStateOpening
:
1585 case MediaStateClosed
:
1586 use_mplayer
= false;
1588 case MediaStateStopped
:
1591 case MediaStateBuffering
:
1592 case MediaStatePlaying
:
1595 case MediaStatePaused
:
1600 // If a seek is pending, we need to return that position.
1602 if (TimeSpan_FromPts (position
) == -1)
1603 position
= element
->mplayer
->GetPosition ();
1604 } else if (use_pause
) {
1605 position
= element
->paused_position
;
1608 if (position
< element
->seeked_to_position
)
1609 position
= element
->seeked_to_position
;
1611 if (TimeSpan_FromPts (position
) == -1) {
1614 position
= MIN (position
, element
->mplayer
->GetDuration ());
1617 this->position
= new Value (TimeSpan_FromPts (position
), Type::TIMESPAN
);
1618 return this->position
;