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 ());
516 UIElement
*parent
= GetVisualParent ();
518 if (parent
&& !parent
->Is (Type::CANVAS
))
519 if (LayoutInformation::GetPreviousConstraint (this) || LayoutInformation::GetLayoutSlot (this))
523 Size available
= Size (INFINITY
, INFINITY
);
524 available
= available
.Min (specified
);
525 result
= MeasureOverride (available
);
528 //g_warning ("actual is %g,%g", result.width, result.height);
534 MediaElement::MeasureOverride (Size availableSize
)
536 Size desired
= availableSize
;
537 Rect shape_bounds
= Rect ();
542 shape_bounds
= Rect (0,0,
543 mplayer
->GetVideoWidth (),
544 mplayer
->GetVideoHeight ());
546 if (GetStretch () == StretchNone
)
547 return desired
.Min (shape_bounds
.width
, shape_bounds
.height
);
549 /* don't stretch to infinite size */
550 if (isinf (desired
.width
))
551 desired
.width
= shape_bounds
.width
;
552 if (isinf (desired
.height
))
553 desired
.height
= shape_bounds
.height
;
555 /* compute the scaling */
556 if (shape_bounds
.width
> 0)
557 sx
= desired
.width
/ shape_bounds
.width
;
558 if (shape_bounds
.height
> 0)
559 sy
= desired
.height
/ shape_bounds
.height
;
561 switch (GetStretch ()) {
563 sx
= sy
= MIN (sx
, sy
);
565 case StretchUniformToFill
:
566 sx
= sy
= MAX (sx
, sy
);
572 desired
= desired
.Min (shape_bounds
.width
* sx
, shape_bounds
.height
* sy
);
578 MediaElement::ArrangeOverride (Size finalSize
)
580 Size arranged
= finalSize
;
581 Rect shape_bounds
= Rect ();
586 shape_bounds
= Rect (0, 0,
587 mplayer
->GetVideoWidth (),
588 mplayer
->GetVideoHeight ());
590 if (GetStretch () == StretchNone
) {
591 arranged
= Size (shape_bounds
.x
+ shape_bounds
.width
,
592 shape_bounds
.y
+ shape_bounds
.height
);
594 if (GetHorizontalAlignment () == HorizontalAlignmentStretch
)
595 arranged
.width
= MAX (arranged
.width
, finalSize
.width
);
597 if (GetVerticalAlignment () == VerticalAlignmentStretch
)
598 arranged
.height
= MAX (arranged
.height
, finalSize
.height
);
604 /* compute the scaling */
605 if (shape_bounds
.width
== 0)
606 shape_bounds
.width
= arranged
.width
;
607 if (shape_bounds
.height
== 0)
608 shape_bounds
.height
= arranged
.height
;
610 if (shape_bounds
.width
!= arranged
.width
)
611 sx
= arranged
.width
/ shape_bounds
.width
;
612 if (shape_bounds
.height
!= arranged
.height
)
613 sy
= arranged
.height
/ shape_bounds
.height
;
615 switch (GetStretch ()) {
617 sx
= sy
= MIN (sx
, sy
);
619 case StretchUniformToFill
:
620 sx
= sy
= MAX (sx
, sy
);
626 arranged
= Size (shape_bounds
.width
* sx
, shape_bounds
.height
* sy
);
632 MediaElement::GetCoverageBounds ()
634 MediaPlayer
*mplayer
= GetMediaPlayer ();
635 Stretch stretch
= GetStretch ();
637 if (IsClosed () || !mplayer
|| !mplayer
->HasRenderedFrame ())
640 if (stretch
== StretchFill
|| stretch
== StretchUniformToFill
)
643 Rect video
= Rect (0, 0, mplayer
->GetVideoWidth (), mplayer
->GetVideoHeight ());
644 cairo_matrix_t brush_xform
= matrix
;
646 cairo_matrix_invert (&brush_xform
);
647 cairo_matrix_multiply (&brush_xform
, &brush_xform
, &absolute_xform
);
649 video
= video
.Transform (&brush_xform
);
650 video
= video
.Intersection (bounds
);
656 MediaElement::Render (cairo_t
*cr
, Region
*region
, bool path_only
)
658 Stretch stretch
= GetStretch ();
659 cairo_surface_t
*surface
;
660 cairo_pattern_t
*pattern
;
662 if (!mplayer
|| !(surface
= mplayer
->GetCairoSurface ()))
666 cairo_set_matrix (cr
, &absolute_xform
);
669 Size
framework (GetActualWidth (), GetActualHeight ());
670 Rect
video (0, 0, mplayer
->GetVideoWidth (), mplayer
->GetVideoHeight ());
672 if (stretch
!= StretchNone
)
673 framework
= ApplySizeConstraints (framework
);
675 Rect
paint (0, 0, framework
.width
, framework
.height
);
678 if (absolute_xform.xy == 0 && absolute_xform.yx == 0) {
679 //cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
680 cairo_matrix_t inv = absolute_xform;
681 cairo_matrix_invert (&inv);
682 paint = paint.Transform (&absolute_xform);
683 paint = paint.RoundIn ();
684 paint = paint.Transform (&inv);
688 image_brush_compute_pattern_matrix (&matrix
,
689 paint
.width
, paint
.height
,
690 video
.width
, video
.height
,
691 stretch
, AlignmentXCenter
,
692 AlignmentYCenter
, NULL
, NULL
);
694 pattern
= cairo_pattern_create_for_surface (surface
);
696 cairo_pattern_set_matrix (pattern
, &matrix
);
698 cairo_set_source (cr
, pattern
);
699 cairo_pattern_destroy (pattern
);
702 cairo_pattern_set_filter (cairo_get_source (cr
), CAIRO_FILTER_FAST
);
705 RenderLayoutClip (cr
);
716 MediaElement::BufferUnderflowHandler (PlaylistRoot
*sender
, EventArgs
*args
)
718 LOG_MEDIAELEMENT ("MediaElement::BufferUnderflow (): Switching to 'Buffering', previous_position: %" G_GUINT64_FORMAT
" ms, mplayer->GetPosition (): %" G_GUINT64_FORMAT
" ms\n",
719 MilliSeconds_FromPts (previous_position
), MilliSeconds_FromPts (mplayer
->GetPosition ()));
721 flags
|= PlayRequested
;
722 SetBufferingProgress (0.0);
723 Emit (BufferingProgressChangedEvent
);
724 SetState (MediaStateBuffering
);
729 MediaElement::EmitStateChangedAsync ()
731 AddTickCallSafe (EmitStateChanged
);
735 MediaElement::EmitStateChanged (EventObject
*obj
)
737 ((MediaElement
*) obj
)->Emit (CurrentStateChangedEvent
);
741 MediaElement::SetState (MediaState state
)
745 LOG_MEDIAELEMENT ("MediaElement::SetState (%d): New state: %s, old state: %s\n",
746 state
, GetStateName (state
), GetStateName (this->state
));
751 if (this->state
!= state
) {
752 prev_state
= this->state
;
758 if (emit
) // Don't emit with mutex locked.
759 EmitStateChangedAsync ();
763 MediaElement::CreatePlaylist ()
765 g_return_if_fail (mplayer
== NULL
);
767 mplayer
= new MediaPlayer (this);
768 SetPlaylist (new PlaylistRoot (this));
772 MediaElement::SetPlaylist (PlaylistRoot
*value
)
774 // if playlist is something, then value must be null (and vice versa)
775 g_return_if_fail ((playlist
== NULL
) != (value
== NULL
));
779 if (playlist
!= NULL
) {
780 playlist
->RemoveAllHandlers (this);
781 playlist
->Dispose ();
785 playlist
= value
; // We assume the caller gives us a reference to the playlist
786 playlist
->AddHandler (PlaylistRoot::OpeningEvent
, OpeningCallback
, this);
787 playlist
->AddHandler (PlaylistRoot::OpenCompletedEvent
, OpenCompletedCallback
, this);
788 playlist
->AddHandler (PlaylistRoot::SeekingEvent
, SeekingCallback
, this);
789 playlist
->AddHandler (PlaylistRoot::SeekCompletedEvent
, SeekCompletedCallback
, this);
790 playlist
->AddHandler (PlaylistRoot::CurrentStateChangedEvent
, CurrentStateChangedCallback
, this);
791 playlist
->AddHandler (PlaylistRoot::MediaErrorEvent
, MediaErrorCallback
, this);
792 playlist
->AddHandler (PlaylistRoot::MediaEndedEvent
, MediaEndedCallback
, this);
793 playlist
->AddHandler (PlaylistRoot::BufferUnderflowEvent
, BufferUnderflowCallback
, this);
794 playlist
->AddHandler (PlaylistRoot::DownloadProgressChangedEvent
, DownloadProgressChangedCallback
, this);
795 playlist
->AddHandler (PlaylistRoot::BufferingProgressChangedEvent
, BufferingProgressChangedCallback
, this);
796 playlist
->AddHandler (PlaylistRoot::PlayEvent
, PlayCallback
, this);
797 playlist
->AddHandler (PlaylistRoot::PauseEvent
, PauseCallback
, this);
798 playlist
->AddHandler (PlaylistRoot::StopEvent
, StopCallback
, this);
799 playlist
->AddHandler (PlaylistRoot::EntryChangedEvent
, EntryChangedCallback
, this);
804 MediaElement::EntryChangedHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
806 LOG_MEDIAELEMENT ("MediaElement::EntryChangedHandler ()\n");
807 flags
&= ~MediaOpenedEmitted
;
811 MediaElement::OpeningHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
813 LOG_MEDIAELEMENT ("MediaElement::OpeningHandler ()\n");
816 SetState (MediaStateOpening
);
820 MediaElement::OpenCompletedHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
822 IMediaDemuxer
*demuxer
;
823 const char *demuxer_name
;
824 PlaylistEntry
*entry
;
829 g_return_if_fail (playlist
!= NULL
);
830 g_return_if_fail (mplayer
!= NULL
);
832 entry
= playlist
->GetCurrentPlaylistEntry ();
834 g_return_if_fail (entry
!= NULL
);
836 media
= entry
->GetMedia ();
838 g_return_if_fail (media
!= NULL
);
840 demuxer
= media
->GetDemuxer ();
841 demuxer_name
= demuxer
->GetName ();
843 LOG_MEDIAELEMENT ("MediaElement::OpenCompletedHandler (%p), demuxer name: %s\n", media
, demuxer_name
);
845 // Try to figure out if we're missing codecs
846 for (int i
= 0; i
< demuxer
->GetStreamCount (); i
++) {
847 IMediaStream
*stream
= demuxer
->GetStream (i
);
848 IMediaDecoder
*decoder
= stream
->GetDecoder ();
849 const char *decoder_name
= decoder
? decoder
->GetName () : NULL
;
850 if (decoder_name
!= NULL
&& strcmp (decoder_name
, "NullDecoder") == 0) {
851 flags
|= MissingCodecs
;
856 // check if we're missing the codecs *and* if they are not installed
857 // since we could already have downloaded/installed them without refreshing the browser (leading to a crash)
858 if ((flags
& MissingCodecs
) && !Media::IsMSCodecsInstalled ())
859 CodecDownloader::ShowUI (GetDeployment ()->GetSurface ());
861 entry
->PopulateMediaAttributes ();
862 SetProperties (media
);
864 if (!(flags
& MediaOpenedEmitted
)) {
865 flags
|= MediaOpenedEmitted
;
869 // This is a workaround for MS DRT #78: it tests that download progress has changed
870 // from the latest DownloadProgressChanged event to the MediaOpened event (unless
871 // DownloadProgress is 0.0 or 1.0).
872 double progress
= media
->GetDownloadProgress ();
873 progress
= MAX (progress
, GetDownloadProgress ());
874 progress
= MIN (progress
+ 0.00000001, 1.0);
875 SetDownloadProgress (progress
);
876 Emit (MediaOpenedEvent
, new RoutedEventArgs ());
877 Emit (DownloadProgressChangedEvent
);
882 MediaElement::SetProperties (Media
*media
)
884 IMediaDemuxer
*demuxer
;
885 PlaylistEntry
*entry
;
886 Duration
*natural_duration
;
887 bool can_seek
= true;
888 bool can_pause
= true;
890 LOG_MEDIAELEMENT ("MediaElement::SetProperties (%p)\n", media
);
892 g_return_if_fail (media
!= NULL
);
893 g_return_if_fail (playlist
!= NULL
);
895 seeked_to_position
= 0;
897 demuxer
= media
->GetDemuxer ();
898 entry
= playlist
->GetCurrentPlaylistEntry ();
900 g_return_if_fail (demuxer
!= NULL
);
901 g_return_if_fail (entry
!= NULL
);
903 ReadMarkers (media
, demuxer
);
906 if (entry
->GetIsLive ()) {
910 can_seek
= entry
->GetClientSkip () && demuxer
->GetCanSeek ();
914 natural_duration
= new Duration (TimeSpan_FromPts (mplayer
->GetDuration ()));
915 SetCanPause (can_pause
);
916 SetCanSeek (can_seek
);
917 SetNaturalDuration (natural_duration
);
918 SetNaturalVideoHeight ((double) mplayer
->GetVideoHeight ());
919 SetNaturalVideoWidth ((double) mplayer
->GetVideoWidth ());
920 SetAudioStreamCount (mplayer
->GetAudioStreamCount ());
922 mplayer
->SetMuted (GetIsMuted ());
923 mplayer
->SetVolume (GetVolume ());
926 InvalidateMeasure ();
927 InvalidateArrange ();
931 MediaElement::SeekingHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
933 LOG_MEDIAELEMENT ("MediaElement::SeekingHandler ()\n");
936 SetMarkerTimeout (false);
940 MediaElement::SeekCompletedHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
942 LOG_MEDIAELEMENT ("MediaElement::SeekCompletedHandler ()\n");
945 if (state
== MediaStatePlaying
)
946 playlist
->PlayAsync ();
948 seek_to_position
= -1;
949 SetMarkerTimeout (true);
953 MediaElement::PlayHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
955 LOG_MEDIAELEMENT ("MediaElement::PlayHandler ()\n");
958 SetMarkerTimeout (true);
960 SetState (MediaStatePlaying
);
964 MediaElement::PauseHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
966 LOG_MEDIAELEMENT ("MediaElement::PauseHandler ()\n");
969 SetMarkerTimeout (false);
971 SetState (MediaStatePaused
);
975 MediaElement::StopHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
977 PlaylistEntry
*entry
;
979 LOG_MEDIAELEMENT ("MediaElement::StopHandler ()\n");
982 g_return_if_fail (playlist
!= NULL
);
984 entry
= playlist
->GetCurrentPlaylistEntry ();
986 g_return_if_fail (entry
!= NULL
);
987 seeked_to_position
= 0;
989 SetProperties (entry
->GetMedia ());
991 SetMarkerTimeout (false);
992 CheckMarkers (); // check one last time.
994 SetState (MediaStateStopped
);
998 MediaElement::CurrentStateChangedHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
1000 LOG_MEDIAELEMENT ("MediaElement::CurrentStateChangedHandler ()\n");
1005 MediaElement::MediaErrorHandler (PlaylistRoot
*playlist
, ErrorEventArgs
*args
)
1007 LOG_MEDIAELEMENT ("MediaElement::MediaErrorHandler (). State: %s Message: %s\n", GetStateName (state
), args
? args
->GetErrorMessage() : NULL
);
1010 if (state
== MediaStateClosed
)
1013 // TODO: Should ClearValue be called on these instead?
1014 SetAudioStreamCount (0);
1015 SetNaturalVideoHeight (0);
1016 SetNaturalVideoWidth (0);
1017 SetNaturalDuration (0);
1018 SetCanPause (false);
1020 SetDownloadProgress (0);
1021 SetDownloadProgressOffset (0);
1022 SetRenderedFramesPerSecond (0);
1023 SetDroppedFramesPerSecond (0);
1026 InvalidateMeasure ();
1027 InvalidateArrange ();
1029 SetState (MediaStateClosed
);
1033 Emit (MediaFailedEvent
, args
);
1037 MediaElement::MediaEndedHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
1039 LOG_MEDIAELEMENT ("MediaElement::MediaEndedHandler ()\n");
1043 paused_position
= GetPosition ();
1044 SetState (MediaStatePaused
);
1045 Emit (MediaEndedEvent
);
1049 MediaElement::DownloadProgressChangedHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
1051 ProgressEventArgs
*pea
= (ProgressEventArgs
*) args
;
1053 LOG_MEDIAELEMENT ("MediaElement::DownloadProgressChangedHandler (): %f\n", pea
? pea
->progress
: -1.0);
1056 g_return_if_fail (pea
!= NULL
);
1058 SetDownloadProgress (pea
->progress
);
1059 Emit (DownloadProgressChangedEvent
);
1063 MediaElement::BufferingProgressChangedHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
1065 ProgressEventArgs
*pea
= (ProgressEventArgs
*) args
;
1067 LOG_MEDIAELEMENT ("MediaElement::BufferingProgressChangedHandler (): %f\n", pea
? pea
->progress
: -1.0);
1070 g_return_if_fail (pea
!= NULL
);
1072 if (GetBufferingProgress () < pea
->progress
) {
1073 SetBufferingProgress (pea
->progress
);
1074 Emit (BufferingProgressChangedEvent
);
1077 if (pea
->progress
>= 1.0 && GetState () == MediaStateBuffering
) {
1078 LOG_MEDIAELEMENT ("MediaElement::BufferingProgressChangedHandler (): buffer full, playing...\n");
1084 MediaElement::MediaInvalidate ()
1086 Emit (MediaInvalidatedEvent
);
1091 MediaElement::SetUriSource (Uri
*uri
)
1093 LOG_MEDIAELEMENT ("MediaElement::SetUriSource ('%s')\n", uri
? uri
->ToString () : NULL
);
1098 g_return_if_fail (playlist
== NULL
);
1100 if (uri
!= NULL
&& uri
->originalString
!= NULL
&& uri
->originalString
[0] != 0) {
1102 char *str
= uri
->ToString ();
1103 playlist
->GetCurrentEntry ()->InitializeWithUri (str
);
1107 InvalidateMeasure ();
1108 InvalidateArrange ();
1113 MediaElement::SetSource (Downloader
*downloader
, const char *PartName
)
1115 LOG_MEDIAELEMENT ("MediaElement::SetSource (%p, '%s')\n", downloader
, PartName
);
1120 g_return_if_fail (downloader
!= NULL
);
1121 g_return_if_fail (playlist
== NULL
);
1124 playlist
->GetCurrentEntry ()->InitializeWithDownloader (downloader
, PartName
);
1128 MediaElement::SetStreamSource (ManagedStreamCallbacks
*callbacks
)
1130 LOG_MEDIAELEMENT ("MediaElement::SetStreamSource (%p)\n", callbacks
);
1135 g_return_if_fail (callbacks
!= NULL
);
1136 g_return_if_fail (playlist
== NULL
);
1139 playlist
->GetCurrentEntry ()->InitializeWithStream (callbacks
);
1141 SetDownloadProgress (1.0);
1145 MediaElement::SetDemuxerSource (void *context
, CloseDemuxerCallback close_demuxer
, GetDiagnosticAsyncCallback get_diagnostic
, GetFrameAsyncCallback get_sample
,
1146 OpenDemuxerAsyncCallback open_demuxer
, SeekAsyncCallback seek
, SwitchMediaStreamAsyncCallback switch_media_stream
)
1148 ExternalDemuxer
*demuxer
;
1151 LOG_MEDIAELEMENT ("MediaElement::SetDemuxerSource (%p)\n", demuxer
);
1156 g_return_val_if_fail (context
!= NULL
, NULL
);
1157 g_return_val_if_fail (close_demuxer
!= NULL
&& get_diagnostic
!= NULL
&& get_sample
!= NULL
&& open_demuxer
!= NULL
&& seek
!= NULL
&& switch_media_stream
!= NULL
, NULL
);
1158 g_return_val_if_fail (playlist
== NULL
, NULL
);
1161 media
= new Media (playlist
);
1162 demuxer
= new ExternalDemuxer (media
, context
, close_demuxer
, get_diagnostic
, get_sample
, open_demuxer
, seek
, switch_media_stream
);
1163 playlist
->GetCurrentEntry ()->InitializeWithDemuxer (demuxer
);
1166 SetDownloadProgress (1.0);
1172 MediaElement::SetPlayRequested ()
1174 LOG_MEDIAELEMENT ("MediaElement::SetPlayRequested ()\n");
1177 flags
|= PlayRequested
;
1181 MediaElement::PlayOrStop ()
1183 LOG_MEDIAELEMENT ("MediaElement::PlayOrPause (): GetCanPause (): %s, PlayRequested: %s, GetAutoPlay: %s, AutoPlayed: %s\n",
1184 GetCanPause () ? "true" : "false", (flags
& PlayRequested
) ? "true" : "false",
1185 GetAutoPlay () ? "true" : "false", (flags
& AutoPlayed
) ? "true" : "false");
1188 if (!GetCanPause ()) {
1189 // If we can't pause, we play
1190 SetState (MediaStatePlaying
);
1191 playlist
->PlayAsync ();
1192 } else if (flags
& PlayRequested
) {
1193 // A Play has already been requested.
1194 SetState (MediaStatePlaying
);
1195 playlist
->PlayAsync ();
1196 } else if (GetAutoPlay () && !(flags
& AutoPlayed
)) {
1198 flags
|= AutoPlayed
;
1199 SetState (MediaStatePlaying
);
1200 playlist
->PlayAsync ();
1202 SetState (MediaStatePaused
);
1207 MediaElement::Pause ()
1209 LOG_MEDIAELEMENT ("MediaElement::Pause (): current state: %s\n", GetStateName (state
));
1212 g_return_if_fail (playlist
!= NULL
);
1215 case MediaStateOpening
:// docs: No specified behaviour
1216 flags
&= ~PlayRequested
;
1218 case MediaStateClosed
: // docs: No specified behaviour
1220 case MediaStatePaused
:// docs: no-op
1221 case MediaStateBuffering
:
1222 case MediaStatePlaying
:
1223 case MediaStateStopped
: // docs: pause
1224 paused_position
= GetPosition ();
1225 SetState (MediaStatePaused
);
1226 playlist
->PauseAsync ();
1228 case MediaStateIndividualizing
:
1229 case MediaStateAcquiringLicense
:
1230 g_warning ("MediaElement: Invalid state.");
1236 MediaElement::Play ()
1238 LOG_MEDIAELEMENT ("MediaElement::Play (): current state: %s\n", GetStateName (state
));
1241 g_return_if_fail (playlist
!= NULL
);
1244 case MediaStateClosed
: // docs: No specified behaviour
1245 case MediaStateOpening
:// docs: No specified behaviour
1246 flags
|= PlayRequested
;
1248 case MediaStatePlaying
:// docs: no-op
1249 case MediaStateBuffering
:
1250 case MediaStatePaused
:
1251 case MediaStateStopped
:
1252 SetState (MediaStatePlaying
);
1253 playlist
->PlayAsync ();
1255 case MediaStateIndividualizing
:
1256 case MediaStateAcquiringLicense
:
1257 g_warning ("MediaElement: Invalid state.");
1263 MediaElement::Stop ()
1265 LOG_MEDIAELEMENT ("MediaElement::Stop (): current state: %s\n", GetStateName (state
));
1268 if (GetSurface () == NULL
)
1272 case MediaStateOpening
:// docs: No specified behaviour
1273 flags
&= ~PlayRequested
;
1275 case MediaStateClosed
: // docs: No specified behaviour
1276 case MediaStateStopped
:// docs: no-op
1278 case MediaStateBuffering
:
1279 case MediaStatePlaying
:
1280 case MediaStatePaused
: // docs: stop
1281 flags
&= ~PlayRequested
;
1283 LOG_MEDIAELEMENT ("MediaElement::Stop (): state: %s, IsSingleFile: %i\n", GetStateName (state
), playlist
->IsSingleFile ());
1285 if (!playlist
->IsSingleFile ())
1286 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).
1288 SetState (MediaStateStopped
);
1289 playlist
->StopAsync ();
1291 case MediaStateIndividualizing
:
1292 case MediaStateAcquiringLicense
:
1293 g_warning ("MediaElement: Invalid state.");
1299 MediaElement::Seek (TimeSpan to
, bool force
)
1301 LOG_MEDIAELEMENT ("MediaElement::Seek (%" G_GUINT64_FORMAT
" = %" G_GUINT64_FORMAT
" ms)\n", to
, MilliSeconds_FromPts (to
));
1304 if (GetSurface () == NULL
)
1307 if (!force
&& !GetCanSeek ()) {
1308 LOG_MEDIAELEMENT ("MediaElement::Seek (): CanSeek is false, not seeking\n");
1313 case MediaStateIndividualizing
:
1314 case MediaStateAcquiringLicense
:
1315 g_warning ("MediaElement:Seek (): Invalid state %s\n", GetStateName (state
));
1317 case MediaStateOpening
:
1318 case MediaStateClosed
:
1322 case MediaStateBuffering
:
1323 case MediaStatePlaying
:
1324 case MediaStatePaused
:
1325 case MediaStateStopped
:
1326 Duration
*duration
= GetNaturalDuration ();
1328 if (duration
->HasTimeSpan () && to
> duration
->GetTimeSpan ())
1329 to
= duration
->GetTimeSpan ();
1333 if (!force
&& to
== TimeSpan_FromPts (mplayer
->GetPosition ()))
1336 previous_position
= to
;
1337 seek_to_position
= to
;
1338 seeked_to_position
= to
;
1339 paused_position
= to
;
1341 mplayer
->NotifySeek (TimeSpan_ToPts (to
));
1342 playlist
->SeekAsync (to
);
1343 Emit (MediaInvalidatedEvent
);
1346 LOG_MEDIAELEMENT ("MediaElement::Seek (%" G_GUINT64_FORMAT
" = %" G_GUINT64_FORMAT
" ms) previous position: %" G_GUINT64_FORMAT
"\n", to
, MilliSeconds_FromPts (to
), previous_position
);
1353 MediaElement::OnPropertyChanged (PropertyChangedEventArgs
*args
, MoonError
*error
)
1355 if (args
->GetId () == MediaElement::SourceProperty
) {
1356 DownloaderAccessPolicy policy
= MediaPolicy
;
1357 Uri
*uri
= GetSource ();
1358 const char *location
;
1361 if (!(location
= GetDeployment ()->GetXapLocation ()) && GetSurface ())
1362 location
= GetSurface ()->GetSourceLocation ();
1364 if (uri
->scheme
&& (!strcmp (uri
->scheme
, "mms") || !strcmp (uri
->scheme
, "rtsp") || !strcmp (uri
->scheme
, "rtsps")))
1365 policy
= StreamingPolicy
;
1367 if (uri
->IsInvalidPath ()) {
1368 EmitAsync (MediaFailedEvent
, new ErrorEventArgs (MediaError
, MoonError (MoonError::ARGUMENT_OUT_OF_RANGE
, 0, "invalid path found in uri")));
1370 } else if (!Downloader::ValidateDownloadPolicy (location
, uri
, policy
)) {
1371 EmitAsync (MediaFailedEvent
, new ErrorEventArgs (MediaError
, MoonError (MoonError::ARGUMENT_OUT_OF_RANGE
, 0, "Security Policy Violation")));
1376 flags
|= RecalculateMatrix
;
1378 } else if (args
->GetId () == MediaElement::AudioStreamIndexProperty
) {
1380 mplayer
->SetAudioStreamIndex (args
->GetNewValue()->AsInt32 ());
1381 } else if (args
->GetId () == MediaElement::AutoPlayProperty
) {
1382 // no state to change
1383 } else if (args
->GetId () == MediaElement::BalanceProperty
) {
1385 mplayer
->SetBalance (args
->GetNewValue()->AsDouble ());
1386 } else if (args
->GetId () == MediaElement::BufferingProgressProperty
) {
1387 // read-only property
1388 } else if (args
->GetId () == MediaElement::BufferingTimeProperty
) {
1390 // Not quite sure what to do here, we could:
1391 // a) store the buffering time on the mediaplayer and let the media request it whenever it needs it
1392 // b) let the media request the buffering time from mediaelement
1393 // 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)
1394 // note that thread-safety is easier with a) (media will do the request from another thread) or c)
1397 media->SetBufferingTime (TimeSpan_ToPts (GetBufferingTime ()));
1399 } else if (args
->GetId () == MediaElement::CurrentStateProperty
) {
1400 // read-only property
1401 // This should really not happen, we use a property provider for this property.
1402 } else if (args
->GetId () == MediaElement::IsMutedProperty
) {
1404 mplayer
->SetMuted (args
->GetNewValue()->AsBool ());
1405 } else if (args
->GetId () == MediaElement::MarkersProperty
) {
1407 } else if (args
->GetId () == MediaElement::NaturalVideoHeightProperty
) {
1408 // read-only property
1409 flags
|= RecalculateMatrix
;
1410 } else if (args
->GetId () == MediaElement::NaturalVideoWidthProperty
) {
1411 // read-only property
1412 flags
|= RecalculateMatrix
;
1413 } else if (args
->GetId () == MediaElement::PositionProperty
) {
1414 Seek (args
->GetNewValue()->AsTimeSpan (), false);
1415 ClearValue (MediaElement::PositionProperty
, false); // We need this, otherwise our property system will return the seeked-to position forever (MediaElementPropertyValueProvider isn't called).
1416 } else if (args
->GetId () == MediaElement::VolumeProperty
) {
1418 mplayer
->SetVolume (args
->GetNewValue()->AsDouble ());
1421 if (args
->GetProperty ()->GetOwnerType() != Type::MEDIAELEMENT
) {
1422 // propagate to parent class
1423 FrameworkElement::OnPropertyChanged (args
, error
);
1424 flags
|= RecalculateMatrix
;
1428 NotifyListenersOfPropertyChange (args
, error
);
1432 MediaElement::EnableAntiAlias (void)
1434 return !(absolute_xform
.xx
== absolute_xform
.yy
&& /* no rotation */
1435 (absolute_xform
.yx
== 0 && absolute_xform
.xy
== 0)); /* no skew */
1440 MediaElement::ReportErrorOccurredCallback (EventObject
*obj
)
1442 MediaElement
*me
= (MediaElement
*) obj
;
1443 ErrorEventArgs
*args
;
1446 args
= me
->error_args
;
1447 me
->error_args
= NULL
;
1448 me
->mutex
.Unlock ();
1450 me
->ReportErrorOccurred (args
);
1456 MediaElement::ReportErrorOccurred (ErrorEventArgs
*args
)
1458 LOG_MEDIAELEMENT ("MediaElement::ReportErrorOccurred (%p)\n", args
);
1460 if (!Surface::InMainThread ()) {
1463 error_args
->unref ();
1468 AddTickCallSafe (ReportErrorOccurredCallback
);
1473 MediaErrorHandler (NULL
, args
);
1477 MediaElement::ReportErrorOccurred (const char *args
)
1479 LOG_MEDIAELEMENT ("MediaElement::ReportErrorOccurred ('%s')\n", args
);
1481 ErrorEventArgs
*eea
= new ErrorEventArgs (MediaError
, MoonError (MoonError::EXCEPTION
, 3001, g_strdup (args
)));
1482 ReportErrorOccurred (eea
);
1487 * MediaElementPropertyValueProvider
1490 MediaElementPropertyValueProvider::MediaElementPropertyValueProvider (MediaElement
*element
, PropertyPrecedence precedence
)
1491 : FrameworkElementProvider (element
, precedence
)
1494 current_state
= NULL
;
1495 rendered_frames_per_second
= NULL
;
1496 dropped_frames_per_second
= NULL
;
1499 MediaElementPropertyValueProvider::~MediaElementPropertyValueProvider ()
1502 delete current_state
;
1503 delete rendered_frames_per_second
;
1504 delete dropped_frames_per_second
;
1508 MediaElementPropertyValueProvider::GetPropertyValue (DependencyProperty
*property
)
1510 // We verify main thread here too in case some object in the pipeline happens to want a property on the media element
1513 if (property
->GetId () == MediaElement::PositionProperty
)
1514 return GetPosition ();
1516 if (property
->GetId () == MediaElement::CurrentStateProperty
)
1517 return GetCurrentState ();
1519 if (property
->GetId () == MediaElement::DroppedFramesPerSecondProperty
)
1520 return GetDroppedFramesPerSecond ();
1522 if (property
->GetId () == MediaElement::RenderedFramesPerSecondProperty
)
1523 return GetRenderedFramesPerSecond ();
1525 return FrameworkElementProvider::GetPropertyValue (property
);
1529 MediaElementPropertyValueProvider::GetDroppedFramesPerSecond ()
1531 MediaElement
*element
= (MediaElement
*) obj
;
1532 MediaPlayer
*mplayer
= element
->GetMediaPlayer ();
1534 delete dropped_frames_per_second
;
1537 dropped_frames_per_second
= new Value (mplayer
->GetDroppedFramesPerSecond ());
1539 dropped_frames_per_second
= NULL
;
1542 return dropped_frames_per_second
;
1546 MediaElementPropertyValueProvider::GetRenderedFramesPerSecond ()
1548 MediaElement
*element
= (MediaElement
*) obj
;
1549 MediaPlayer
*mplayer
= element
->GetMediaPlayer ();
1551 delete rendered_frames_per_second
;
1554 rendered_frames_per_second
= new Value (mplayer
->GetRenderedFramesPerSecond ());
1556 rendered_frames_per_second
= NULL
;
1559 return rendered_frames_per_second
;
1563 MediaElementPropertyValueProvider::GetCurrentState ()
1565 MediaElement
*element
= (MediaElement
*) obj
;
1567 delete current_state
;
1568 current_state
= new Value (element
->state
);
1570 return current_state
;
1574 MediaElementPropertyValueProvider::GetPosition ()
1576 bool use_mplayer
= false;;
1577 bool use_pause
= false;
1578 MediaElement
*element
= (MediaElement
*) obj
;
1579 guint64 position
= TimeSpan_ToPts (element
->seek_to_position
);
1581 delete this->position
;
1582 this->position
= NULL
;
1584 switch (element
->state
) {
1585 case MediaStateIndividualizing
:
1586 case MediaStateAcquiringLicense
:
1587 g_warning ("MediaElementPropertyValueProvider::GetPosition (): Invalid state.\n");
1589 case MediaStateOpening
:
1590 case MediaStateClosed
:
1591 use_mplayer
= false;
1593 case MediaStateStopped
:
1596 case MediaStateBuffering
:
1597 case MediaStatePlaying
:
1600 case MediaStatePaused
:
1605 // If a seek is pending, we need to return that position.
1607 if (TimeSpan_FromPts (position
) == -1)
1608 position
= element
->mplayer
->GetPosition ();
1609 } else if (use_pause
) {
1610 position
= element
->paused_position
;
1613 if (position
< element
->seeked_to_position
)
1614 position
= element
->seeked_to_position
;
1616 if (TimeSpan_FromPts (position
) == -1) {
1619 position
= MIN (position
, element
->mplayer
->GetDuration ());
1622 this->position
= new Value (TimeSpan_FromPts (position
), Type::TIMESPAN
);
1623 return this->position
;