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),
65 Initializing
= (1 << 16),
72 MediaElement::MediaElement ()
74 SetObjectType (Type::MEDIAELEMENT
);
76 streamed_markers
= NULL
;
77 streamed_markers_queue
= NULL
;
78 marker_closure
= NULL
;
82 flags
= UseMediaWidth
| UseMediaHeight
;
89 providers
[PropertyPrecedence_DynamicValue
] = new MediaElementPropertyValueProvider (this, PropertyPrecedence_DynamicValue
);
91 // Note: BufferingTime and Position need to be set in the ctor
92 // so that ReadLocalValue() will get these values.
93 SetValue (MediaElement::BufferingTimeProperty
, Value (TimeSpan_FromSeconds (5), Type::TIMESPAN
));
94 SetValue (MediaElement::PositionProperty
, Value (TimeSpan_FromSeconds (0), Type::TIMESPAN
));
96 GetDeployment ()->AddHandler (Deployment::ShuttingDownEvent
, ShuttingDownCallback
, this);
100 MediaElement::Dispose ()
102 LOG_MEDIAELEMENT ("MediaElement::Dispose ()\n");
105 GetDeployment ()->RemoveHandler (Deployment::ShuttingDownEvent
, ShuttingDownCallback
, this);
108 FrameworkElement::Dispose ();
112 MediaElement::ShuttingDownHandler (Deployment
*sender
, EventArgs
*args
)
114 LOG_MEDIAELEMENT ("MediaElement::ShuttingDownHandler ()\n");
120 MediaElement::GetStateName (MediaState state
)
122 return enums_int_to_str ("MediaState", state
);
126 MediaElement::AddStreamedMarkerCallback (MediaClosure
*c
)
128 MediaMarkerFoundClosure
*closure
= (MediaMarkerFoundClosure
*) c
;
129 MediaElement
*element
= (MediaElement
*) closure
->GetContext ();
130 MediaMarker
*mmarker
= closure
->GetMarker ();
137 element
->AddStreamedMarker (mmarker
);
139 return MEDIA_SUCCESS
;
143 MediaElement::AddStreamedMarker (MediaMarker
*mmarker
)
146 TimelineMarker
*marker
;
148 g_return_if_fail (mmarker
!= NULL
);
150 pts
= mmarker
->Pts ();
152 marker
= new TimelineMarker ();
153 marker
->SetText (mmarker
->Text ());
154 marker
->SetType (mmarker
->Type ());
155 marker
->SetTime (pts
);
157 AddStreamedMarker (marker
);
162 MediaElement::AddStreamedMarker (TimelineMarker
*marker
)
164 LOG_MEDIAELEMENT ("MediaElement::AddStreamedMarker (): got marker %s, %s, %" G_GUINT64_FORMAT
" = %" G_GUINT64_FORMAT
" ms\n",
165 marker
->GetText (), marker
->GetType (), marker
->GetTime (),
166 MilliSeconds_FromPts (marker
->GetTime ()));
171 if (streamed_markers_queue
== NULL
)
172 streamed_markers_queue
= new List ();
173 streamed_markers_queue
->Append (new TimelineMarkerNode (marker
));
178 MediaElement::ReadMarkers (Media
*media
, IMediaDemuxer
*demuxer
)
180 LOG_MEDIAELEMENT ("MediaElement::ReadMarkers ()\n");
183 g_return_if_fail (demuxer
!= NULL
);
184 g_return_if_fail (media
!= NULL
);
186 for (int i
= 0; i
< demuxer
->GetStreamCount (); i
++) {
187 if (demuxer
->GetStream (i
)->GetType () == MediaTypeMarker
) {
188 MarkerStream
*stream
= (MarkerStream
*) demuxer
->GetStream (i
);
190 if (marker_closure
== NULL
)
191 marker_closure
= new MediaMarkerFoundClosure (media
, AddStreamedMarkerCallback
, this);
193 stream
->SetCallback (marker_closure
);
195 MediaMarker
*m
= stream
->Pop ();
197 AddStreamedMarker (m
);
205 TimelineMarkerCollection
*markers
= NULL
;
206 MediaMarker::Node
*current
= (MediaMarker::Node
*) media
->GetMarkers ()->First ();
208 if (current
== NULL
) {
209 //printf ("MediaElement::ReadMarkers (): no markers.\n");
213 markers
= new TimelineMarkerCollection ();
214 while (current
!= NULL
) {
215 TimelineMarker
*new_marker
= new TimelineMarker ();
216 MediaMarker
*marker
= current
->marker
;
218 new_marker
->SetText (marker
->Text ());
219 new_marker
->SetType (marker
->Type ());
220 new_marker
->SetTime (TimeSpan_FromPts (marker
->Pts ()));
225 new_marker
->unref ();
227 current
= (MediaMarker::Node
*) current
->next
;
230 // Docs says we overwrite whatever's been loaded already.
231 LOG_MEDIAELEMENT ("MediaElement::ReadMarkers (): setting %d markers.\n", markers
->GetCount ());
232 SetMarkers (markers
);
237 MediaElement::MarkerTimeout (gpointer context
)
240 ((MediaElement
*) context
)->SetCurrentDeployment ();
241 ((MediaElement
*) context
)->CheckMarkers ();
246 MediaElement::SetMarkerTimeout (bool start
)
253 surface
= GetDeployment ()->GetSurface ();
258 tm
= surface
->GetTimeManager ();
260 g_return_if_fail (tm
!= NULL
);
263 if (marker_timeout
== 0) {
264 marker_timeout
= tm
->AddTimeout (MOON_PRIORITY_DEFAULT
, 33, MarkerTimeout
, this);
267 if (marker_timeout
!= 0) {
268 tm
->RemoveTimeout (marker_timeout
);
275 MediaElement::CheckMarkers ()
277 guint64 current_position
= GetPosition ();
279 LOG_MARKERS_EX ("MediaElement::CheckMarkers () current position: %" G_GUINT64_FORMAT
", previous position: %" G_GUINT64_FORMAT
")\n", current_position
, previous_position
);
282 if (current_position
> previous_position
&& seek_to_position
== -1) {
283 guint64 tmp
= previous_position
;
284 // We need to set previous_position before calling CheckMarkers,
285 // as CheckMarkers may end up emitting events, causing seeks
286 // which will change previous_position.
287 previous_position
= current_position
;
288 CheckMarkers (tmp
, current_position
- 1);
293 MediaElement::CheckMarkers (guint64 from
, guint64 to
)
295 TimelineMarkerCollection
*markers
;
297 LOG_MARKERS_EX ("MediaElement::CheckMarkers (%" G_GUINT64_FORMAT
", %" G_GUINT64_FORMAT
")\n", from
, to
);
301 LOG_MARKERS ("MediaElement::CheckMarkers (%" G_GUINT64_FORMAT
", %" G_GUINT64_FORMAT
"). from == to\n", from
, to
);
305 if (!(markers
= GetMarkers ())) {
306 LOG_MARKERS ("MediaElement::CheckMarkers (%" G_GUINT64_FORMAT
", %" G_GUINT64_FORMAT
"). No markers\n", from
, to
);
311 // if from > to we've seeked backwards (last played position is after this one)
312 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
));
316 /* Check if we've got streamed markers */
318 if (streamed_markers_queue
!= NULL
) {
319 TimelineMarkerNode
*node
= (TimelineMarkerNode
*) streamed_markers_queue
->First ();
320 while (node
!= NULL
) {
321 if (streamed_markers
== NULL
)
322 streamed_markers
= new TimelineMarkerCollection ();
323 streamed_markers
->Add (node
->GetTimelineMarker ());
324 node
= (TimelineMarkerNode
*) node
->next
;
326 streamed_markers_queue
->Clear (true);
330 CheckMarkers (from
, to
, markers
, false);
331 CheckMarkers (from
, to
, streamed_markers
, true);
335 MediaElement::CheckMarkers (guint64 from
, guint64 to
, TimelineMarkerCollection
*markers
, bool remove
)
337 TimelineMarker
*marker
;
343 LOG_MARKERS ("MediaElement::CheckMarkers (%" G_GUINT64_FORMAT
", %" G_GUINT64_FORMAT
", %p, %i). count: %i\n", from
, to
, markers
, remove
, markers
? markers
->GetCount () : -1);
346 // We might want to use a more intelligent algorithm here,
347 // this code only loops through all markers on every frame.
349 if (markers
!= NULL
) {
350 for (int i
= 0; i
< markers
->GetCount (); i
++) {
351 marker
= markers
->GetValueAt (i
)->AsTimelineMarker ();
353 if (!(val
= marker
->GetValue (TimelineMarker::TimeProperty
)))
356 pts
= (guint64
) val
->AsTimeSpan ();
358 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 ());
362 // Streamed markers. Emit these even if we passed them with up to 1 s.
363 if (from
<= MilliSeconds_ToPts (1000)) {
364 emit
= pts
>= 0 && pts
<= to
;
366 emit
= pts
>= (from
- MilliSeconds_ToPts (1000)) && pts
<= to
;
369 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",
370 from
<= MilliSeconds_ToPts (1000) ? 0 : from
- MilliSeconds_ToPts (1000), to
, emit
, pts
, marker
->GetText (), marker
->GetType ());
373 emit
= pts
>= from
&& pts
<= to
;
374 LOG_MARKERS_EX ("MediaElement::CheckMarkers (%" G_GUINT64_FORMAT
", %" G_GUINT64_FORMAT
"): Checking pts: %" G_GUINT64_FORMAT
" in marker with Text = %s, Type = %s\n",
375 from
, to
, pts
, marker
->GetText (), marker
->GetType ());
380 emit_list
.Add (marker
);
382 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",
383 from
, to
, marker
->GetText (), marker
->GetType (), marker
->GetTime (), MilliSeconds_FromPts (marker
->GetTime ()), emit_list
.GetCount ());
386 if (remove
&& (pts
<= to
|| emit
)) {
387 // Also delete markers we've passed by already
388 markers
->RemoveAt (i
);
394 for (int i
= 0; i
< emit_list
.GetCount (); i
++) {
395 marker
= (TimelineMarker
*) emit_list
[i
];
396 Emit (MarkerReachedEvent
, new MarkerReachedEventArgs (marker
));
402 MediaElement::SetSurface (Surface
*s
)
406 if (GetSurface() == s
)
410 mplayer
->SetSurface (s
);
413 LOG_PIPELINE ("MediaElement::SetSurface (%p): Stopping media element since we're detached.\n", s
);
415 mplayer
->Stop (); /* this is immediate */
416 Stop (); /* this is async */
419 if (!SetSurfaceLock ())
421 FrameworkElement::SetSurface (s
);
426 MediaElement::Reinitialize ()
428 TimelineMarkerCollection
*markers
;
429 MediaAttributeCollection
*attrs
;
431 LOG_MEDIAELEMENT ("MediaElement::Reinitialize ()\n");
440 if (marker_closure
) {
441 marker_closure
->Dispose ();
442 marker_closure
->unref ();
443 marker_closure
= NULL
;
446 if (playlist
!= NULL
) {
447 playlist
->Dispose ();
452 flags
&= (PlayRequested
| UseMediaHeight
| UseMediaWidth
);
453 flags
|= RecalculateMatrix
;
455 prev_state
= MediaStateClosed
;
456 state
= MediaStateClosed
;
459 first_pts
= G_MAXUINT64
;
460 seek_to_position
= -1;
461 seeked_to_position
= 0;
466 delete streamed_markers_queue
;
467 streamed_markers_queue
= NULL
;
468 if (streamed_markers
) {
469 streamed_markers
->unref ();
470 streamed_markers
= NULL
;
473 error_args
->unref ();
478 previous_position
= 0;
480 SetMarkerTimeout (false);
481 if ((markers
= GetMarkers ()))
484 if ((attrs
= GetAttributes ()))
487 cairo_matrix_init_identity (&matrix
);
491 MediaElement::IsMissingCodecs ()
494 return flags
& MissingCodecs
;
498 MediaElement::GetTransformOrigin ()
500 Point
*user_xform_origin
= GetRenderTransformOrigin ();
501 double h
= GetActualHeight();
502 double w
= GetActualWidth ();
504 if (w
== 0.0 && h
== 0.0 && mplayer
!= NULL
) {
505 h
= (double) mplayer
->GetVideoHeight ();
506 w
= (double) mplayer
->GetVideoWidth ();
509 return Point (user_xform_origin
->x
* w
, user_xform_origin
->y
* h
);
513 MediaElement::ComputeActualSize ()
515 Size result
= FrameworkElement::ComputeActualSize ();
516 Size specified
= Size (GetWidth (), GetHeight ());
517 UIElement
*parent
= GetVisualParent ();
519 if (parent
&& !parent
->Is (Type::CANVAS
))
520 if (LayoutInformation::GetPreviousConstraint (this) || LayoutInformation::GetLayoutSlot (this))
524 Size available
= Size (INFINITY
, INFINITY
);
525 available
= available
.Min (specified
);
526 result
= MeasureOverride (available
);
529 //g_warning ("actual is %g,%g", result.width, result.height);
535 MediaElement::MeasureOverride (Size availableSize
)
537 Size desired
= availableSize
;
538 Rect shape_bounds
= Rect ();
543 shape_bounds
= Rect (0,0,
544 mplayer
->GetVideoWidth (),
545 mplayer
->GetVideoHeight ());
547 if (GetStretch () == StretchNone
)
548 return desired
.Min (shape_bounds
.width
, shape_bounds
.height
);
550 /* don't stretch to infinite size */
551 if (isinf (desired
.width
))
552 desired
.width
= shape_bounds
.width
;
553 if (isinf (desired
.height
))
554 desired
.height
= shape_bounds
.height
;
556 /* compute the scaling */
557 if (shape_bounds
.width
> 0)
558 sx
= desired
.width
/ shape_bounds
.width
;
559 if (shape_bounds
.height
> 0)
560 sy
= desired
.height
/ shape_bounds
.height
;
562 switch (GetStretch ()) {
564 sx
= sy
= MIN (sx
, sy
);
566 case StretchUniformToFill
:
567 sx
= sy
= MAX (sx
, sy
);
573 desired
= desired
.Min (shape_bounds
.width
* sx
, shape_bounds
.height
* sy
);
579 MediaElement::ArrangeOverride (Size finalSize
)
581 Size arranged
= finalSize
;
582 Rect shape_bounds
= Rect ();
587 shape_bounds
= Rect (0, 0,
588 mplayer
->GetVideoWidth (),
589 mplayer
->GetVideoHeight ());
591 if (GetStretch () == StretchNone
) {
592 arranged
= Size (shape_bounds
.x
+ shape_bounds
.width
,
593 shape_bounds
.y
+ shape_bounds
.height
);
595 if (GetHorizontalAlignment () == HorizontalAlignmentStretch
)
596 arranged
.width
= MAX (arranged
.width
, finalSize
.width
);
598 if (GetVerticalAlignment () == VerticalAlignmentStretch
)
599 arranged
.height
= MAX (arranged
.height
, finalSize
.height
);
605 /* compute the scaling */
606 if (shape_bounds
.width
== 0)
607 shape_bounds
.width
= arranged
.width
;
608 if (shape_bounds
.height
== 0)
609 shape_bounds
.height
= arranged
.height
;
611 if (shape_bounds
.width
!= arranged
.width
)
612 sx
= arranged
.width
/ shape_bounds
.width
;
613 if (shape_bounds
.height
!= arranged
.height
)
614 sy
= arranged
.height
/ shape_bounds
.height
;
616 switch (GetStretch ()) {
618 sx
= sy
= MIN (sx
, sy
);
620 case StretchUniformToFill
:
621 sx
= sy
= MAX (sx
, sy
);
627 arranged
= Size (shape_bounds
.width
* sx
, shape_bounds
.height
* sy
);
633 MediaElement::GetCoverageBounds ()
635 MediaPlayer
*mplayer
= GetMediaPlayer ();
636 Stretch stretch
= GetStretch ();
638 if (IsClosed () || !mplayer
|| !mplayer
->HasRenderedFrame ())
641 if (stretch
== StretchFill
|| stretch
== StretchUniformToFill
)
644 Rect video
= Rect (0, 0, mplayer
->GetVideoWidth (), mplayer
->GetVideoHeight ());
645 cairo_matrix_t brush_xform
= matrix
;
647 cairo_matrix_invert (&brush_xform
);
648 cairo_matrix_multiply (&brush_xform
, &brush_xform
, &absolute_xform
);
650 video
= video
.Transform (&brush_xform
);
651 video
= video
.Intersection (bounds
);
657 MediaElement::Render (cairo_t
*cr
, Region
*region
, bool path_only
)
659 Stretch stretch
= GetStretch ();
660 cairo_surface_t
*surface
;
661 cairo_pattern_t
*pattern
;
663 if (!mplayer
|| !(surface
= mplayer
->GetCairoSurface ()))
667 cairo_set_matrix (cr
, &absolute_xform
);
670 Size
framework (GetActualWidth (), GetActualHeight ());
671 Rect
video (0, 0, mplayer
->GetVideoWidth (), mplayer
->GetVideoHeight ());
673 if (stretch
!= StretchNone
)
674 framework
= ApplySizeConstraints (framework
);
676 Rect
paint (0, 0, framework
.width
, framework
.height
);
679 if (absolute_xform.xy == 0 && absolute_xform.yx == 0) {
680 //cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
681 cairo_matrix_t inv = absolute_xform;
682 cairo_matrix_invert (&inv);
683 paint = paint.Transform (&absolute_xform);
684 paint = paint.RoundIn ();
685 paint = paint.Transform (&inv);
689 image_brush_compute_pattern_matrix (&matrix
,
690 paint
.width
, paint
.height
,
691 video
.width
, video
.height
,
692 stretch
, AlignmentXCenter
,
693 AlignmentYCenter
, NULL
, NULL
);
695 pattern
= cairo_pattern_create_for_surface (surface
);
697 cairo_pattern_set_matrix (pattern
, &matrix
);
699 cairo_set_source (cr
, pattern
);
700 cairo_pattern_destroy (pattern
);
703 cairo_pattern_set_filter (cairo_get_source (cr
), CAIRO_FILTER_FAST
);
706 RenderLayoutClip (cr
);
717 MediaElement::BufferUnderflowHandler (PlaylistRoot
*sender
, EventArgs
*args
)
719 LOG_MEDIAELEMENT ("MediaElement::BufferUnderflow (): Switching to 'Buffering', previous_position: %" G_GUINT64_FORMAT
" ms, mplayer->GetPosition (): %" G_GUINT64_FORMAT
" ms\n",
720 MilliSeconds_FromPts (previous_position
), MilliSeconds_FromPts (mplayer
->GetPosition ()));
722 flags
|= PlayRequested
;
723 SetBufferingProgress (0.0);
724 Emit (BufferingProgressChangedEvent
);
725 SetState (MediaStateBuffering
);
730 MediaElement::EmitStateChangedAsync ()
732 AddTickCallSafe (EmitStateChanged
);
736 MediaElement::EmitStateChanged (EventObject
*obj
)
738 ((MediaElement
*) obj
)->Emit (CurrentStateChangedEvent
);
742 MediaElement::SetState (MediaState state
)
746 LOG_MEDIAELEMENT ("MediaElement::SetState (%d): New state: %s, old state: %s\n",
747 state
, GetStateName (state
), GetStateName (this->state
));
752 if (this->state
!= state
) {
753 prev_state
= this->state
;
759 if (emit
) // Don't emit with mutex locked.
760 EmitStateChangedAsync ();
764 MediaElement::CreatePlaylist ()
766 g_return_if_fail (mplayer
== NULL
);
768 mplayer
= new MediaPlayer (this);
769 SetPlaylist (new PlaylistRoot (this));
773 MediaElement::SetPlaylist (PlaylistRoot
*value
)
775 // if playlist is something, then value must be null (and vice versa)
776 g_return_if_fail ((playlist
== NULL
) != (value
== NULL
));
780 if (playlist
!= NULL
) {
781 playlist
->RemoveAllHandlers (this);
782 playlist
->Dispose ();
786 playlist
= value
; // We assume the caller gives us a reference to the playlist
787 playlist
->AddHandler (PlaylistRoot::OpeningEvent
, OpeningCallback
, this);
788 playlist
->AddHandler (PlaylistRoot::OpenCompletedEvent
, OpenCompletedCallback
, this);
789 playlist
->AddHandler (PlaylistRoot::SeekingEvent
, SeekingCallback
, this);
790 playlist
->AddHandler (PlaylistRoot::SeekCompletedEvent
, SeekCompletedCallback
, this);
791 playlist
->AddHandler (PlaylistRoot::CurrentStateChangedEvent
, CurrentStateChangedCallback
, this);
792 playlist
->AddHandler (PlaylistRoot::MediaErrorEvent
, MediaErrorCallback
, this);
793 playlist
->AddHandler (PlaylistRoot::MediaEndedEvent
, MediaEndedCallback
, this);
794 playlist
->AddHandler (PlaylistRoot::BufferUnderflowEvent
, BufferUnderflowCallback
, this);
795 playlist
->AddHandler (PlaylistRoot::DownloadProgressChangedEvent
, DownloadProgressChangedCallback
, this);
796 playlist
->AddHandler (PlaylistRoot::BufferingProgressChangedEvent
, BufferingProgressChangedCallback
, this);
797 playlist
->AddHandler (PlaylistRoot::PlayEvent
, PlayCallback
, this);
798 playlist
->AddHandler (PlaylistRoot::PauseEvent
, PauseCallback
, this);
799 playlist
->AddHandler (PlaylistRoot::StopEvent
, StopCallback
, this);
800 playlist
->AddHandler (PlaylistRoot::EntryChangedEvent
, EntryChangedCallback
, this);
805 MediaElement::EntryChangedHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
807 LOG_MEDIAELEMENT ("MediaElement::EntryChangedHandler ()\n");
808 flags
&= ~MediaOpenedEmitted
;
812 MediaElement::OpeningHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
814 LOG_MEDIAELEMENT ("MediaElement::OpeningHandler ()\n");
817 flags
&= ~Initializing
;
818 SetState (MediaStateOpening
);
822 MediaElement::OpenCompletedHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
824 IMediaDemuxer
*demuxer
;
825 const char *demuxer_name
;
826 PlaylistEntry
*entry
;
831 g_return_if_fail (playlist
!= NULL
);
832 g_return_if_fail (mplayer
!= NULL
);
834 entry
= playlist
->GetCurrentPlaylistEntry ();
836 g_return_if_fail (entry
!= NULL
);
838 media
= entry
->GetMedia ();
840 g_return_if_fail (media
!= NULL
);
842 demuxer
= media
->GetDemuxer ();
843 demuxer_name
= demuxer
->GetName ();
845 LOG_MEDIAELEMENT ("MediaElement::OpenCompletedHandler (%p), demuxer name: %s\n", media
, demuxer_name
);
847 // Try to figure out if we're missing codecs
848 for (int i
= 0; i
< demuxer
->GetStreamCount (); i
++) {
849 IMediaStream
*stream
= demuxer
->GetStream (i
);
850 IMediaDecoder
*decoder
= stream
->GetDecoder ();
851 const char *decoder_name
= decoder
? decoder
->GetName () : NULL
;
852 if (decoder_name
!= NULL
&& strcmp (decoder_name
, "NullDecoder") == 0) {
853 flags
|= MissingCodecs
;
858 // check if we're missing the codecs *and* if they are not installed
859 // since we could already have downloaded/installed them without refreshing the browser (leading to a crash)
860 if ((flags
& MissingCodecs
) && !Media::IsMSCodecsInstalled ())
861 CodecDownloader::ShowUI (GetDeployment ()->GetSurface ());
863 entry
->PopulateMediaAttributes ();
864 SetProperties (media
);
866 if (!(flags
& MediaOpenedEmitted
)) {
867 flags
|= MediaOpenedEmitted
;
871 // This is a workaround for MS DRT #78: it tests that download progress has changed
872 // from the latest DownloadProgressChanged event to the MediaOpened event (unless
873 // DownloadProgress is 0.0 or 1.0).
874 double progress
= media
->GetDownloadProgress ();
875 progress
= MAX (progress
, GetDownloadProgress ());
876 progress
= MIN (progress
+ 0.00000001, 1.0);
877 SetDownloadProgress (progress
);
878 Emit (MediaOpenedEvent
, new RoutedEventArgs ());
879 Emit (DownloadProgressChangedEvent
);
884 MediaElement::SetProperties (Media
*media
)
886 IMediaDemuxer
*demuxer
;
887 PlaylistEntry
*entry
;
888 Duration
*natural_duration
;
889 bool can_seek
= true;
890 bool can_pause
= true;
892 LOG_MEDIAELEMENT ("MediaElement::SetProperties (%p)\n", media
);
894 g_return_if_fail (media
!= NULL
);
895 g_return_if_fail (playlist
!= NULL
);
897 seeked_to_position
= 0;
899 demuxer
= media
->GetDemuxer ();
900 entry
= playlist
->GetCurrentPlaylistEntry ();
902 g_return_if_fail (demuxer
!= NULL
);
903 g_return_if_fail (entry
!= NULL
);
905 ReadMarkers (media
, demuxer
);
908 if (entry
->GetIsLive ()) {
912 can_seek
= entry
->GetClientSkip () && demuxer
->GetCanSeek ();
916 natural_duration
= new Duration (TimeSpan_FromPts (mplayer
->GetDuration ()));
917 SetCanPause (can_pause
);
918 SetCanSeek (can_seek
);
919 SetNaturalDuration (natural_duration
);
920 SetNaturalVideoHeight ((double) mplayer
->GetVideoHeight ());
921 SetNaturalVideoWidth ((double) mplayer
->GetVideoWidth ());
922 SetAudioStreamCount (mplayer
->GetAudioStreamCount ());
924 mplayer
->SetMuted (GetIsMuted ());
925 mplayer
->SetVolume (GetVolume ());
928 InvalidateMeasure ();
929 InvalidateArrange ();
933 MediaElement::SeekingHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
935 LOG_MEDIAELEMENT ("MediaElement::SeekingHandler ()\n");
938 SetMarkerTimeout (false);
942 MediaElement::SeekCompletedHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
944 LOG_MEDIAELEMENT ("MediaElement::SeekCompletedHandler ()\n");
947 if (state
== MediaStatePlaying
)
948 playlist
->PlayAsync ();
950 seek_to_position
= -1;
951 SetMarkerTimeout (true);
955 MediaElement::PlayHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
957 LOG_MEDIAELEMENT ("MediaElement::PlayHandler ()\n");
960 SetMarkerTimeout (true);
962 SetState (MediaStatePlaying
);
966 MediaElement::PauseHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
968 LOG_MEDIAELEMENT ("MediaElement::PauseHandler ()\n");
971 SetMarkerTimeout (false);
973 SetState (MediaStatePaused
);
977 MediaElement::StopHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
979 PlaylistEntry
*entry
;
981 LOG_MEDIAELEMENT ("MediaElement::StopHandler ()\n");
984 g_return_if_fail (playlist
!= NULL
);
986 entry
= playlist
->GetCurrentPlaylistEntry ();
988 g_return_if_fail (entry
!= NULL
);
989 seeked_to_position
= 0;
991 SetProperties (entry
->GetMedia ());
993 SetMarkerTimeout (false);
994 CheckMarkers (); // check one last time.
996 SetState (MediaStateStopped
);
1000 MediaElement::CurrentStateChangedHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
1002 LOG_MEDIAELEMENT ("MediaElement::CurrentStateChangedHandler ()\n");
1007 MediaElement::MediaErrorHandler (PlaylistRoot
*playlist
, ErrorEventArgs
*args
)
1009 LOG_MEDIAELEMENT ("MediaElement::MediaErrorHandler (). State: %s Message: %s\n", GetStateName (state
), args
? args
->GetErrorMessage() : NULL
);
1012 if (state
== MediaStateClosed
&& !(flags
& Initializing
))
1015 // TODO: Should ClearValue be called on these instead?
1016 SetAudioStreamCount (0);
1017 SetNaturalVideoHeight (0);
1018 SetNaturalVideoWidth (0);
1019 SetNaturalDuration (0);
1020 SetCanPause (false);
1022 SetDownloadProgress (0);
1023 SetDownloadProgressOffset (0);
1024 SetRenderedFramesPerSecond (0);
1025 SetDroppedFramesPerSecond (0);
1028 InvalidateMeasure ();
1029 InvalidateArrange ();
1031 SetState (MediaStateClosed
);
1036 if (flags
& Initializing
)
1037 EmitAsync (MediaFailedEvent
, args
);
1039 Emit (MediaFailedEvent
, args
);
1041 flags
&= ~Initializing
;
1045 MediaElement::MediaEndedHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
1047 LOG_MEDIAELEMENT ("MediaElement::MediaEndedHandler ()\n");
1051 paused_position
= GetPosition ();
1052 SetState (MediaStatePaused
);
1053 Emit (MediaEndedEvent
);
1057 MediaElement::DownloadProgressChangedHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
1059 ProgressEventArgs
*pea
= (ProgressEventArgs
*) args
;
1061 LOG_MEDIAELEMENT ("MediaElement::DownloadProgressChangedHandler (): %f\n", pea
? pea
->progress
: -1.0);
1064 g_return_if_fail (pea
!= NULL
);
1066 SetDownloadProgress (pea
->progress
);
1067 Emit (DownloadProgressChangedEvent
);
1071 MediaElement::BufferingProgressChangedHandler (PlaylistRoot
*playlist
, EventArgs
*args
)
1073 ProgressEventArgs
*pea
= (ProgressEventArgs
*) args
;
1075 LOG_MEDIAELEMENT ("MediaElement::BufferingProgressChangedHandler (): %f\n", pea
? pea
->progress
: -1.0);
1078 g_return_if_fail (pea
!= NULL
);
1080 if (GetBufferingProgress () < pea
->progress
) {
1081 SetBufferingProgress (pea
->progress
);
1082 Emit (BufferingProgressChangedEvent
);
1085 if (pea
->progress
>= 1.0 && GetState () == MediaStateBuffering
) {
1086 LOG_MEDIAELEMENT ("MediaElement::BufferingProgressChangedHandler (): buffer full, playing...\n");
1092 MediaElement::MediaInvalidate ()
1094 Emit (MediaInvalidatedEvent
);
1099 MediaElement::SetUriSource (Uri
*uri
)
1101 LOG_MEDIAELEMENT ("MediaElement::SetUriSource ('%s')\n", uri
? uri
->ToString () : NULL
);
1106 g_return_if_fail (playlist
== NULL
);
1108 flags
|= Initializing
;
1110 if (uri
!= NULL
&& uri
->originalString
!= NULL
&& uri
->originalString
[0] != 0) {
1112 char *str
= uri
->ToString ();
1113 playlist
->GetCurrentEntry ()->InitializeWithUri (str
);
1117 InvalidateMeasure ();
1118 InvalidateArrange ();
1121 flags
&= ~Initializing
;
1125 MediaElement::SetSource (Downloader
*downloader
, const char *PartName
)
1127 LOG_MEDIAELEMENT ("MediaElement::SetSource (%p, '%s')\n", downloader
, PartName
);
1132 g_return_if_fail (downloader
!= NULL
);
1133 g_return_if_fail (playlist
== NULL
);
1135 flags
|= Initializing
;
1138 playlist
->GetCurrentEntry ()->InitializeWithDownloader (downloader
, PartName
);
1140 flags
&= ~Initializing
;
1144 MediaElement::SetStreamSource (ManagedStreamCallbacks
*callbacks
)
1146 LOG_MEDIAELEMENT ("MediaElement::SetStreamSource (%p)\n", callbacks
);
1151 g_return_if_fail (callbacks
!= NULL
);
1152 g_return_if_fail (playlist
== NULL
);
1154 flags
|= Initializing
;
1157 playlist
->GetCurrentEntry ()->InitializeWithStream (callbacks
);
1159 SetDownloadProgress (1.0);
1161 flags
&= ~Initializing
;
1165 MediaElement::SetDemuxerSource (void *context
, CloseDemuxerCallback close_demuxer
, GetDiagnosticAsyncCallback get_diagnostic
, GetFrameAsyncCallback get_sample
,
1166 OpenDemuxerAsyncCallback open_demuxer
, SeekAsyncCallback seek
, SwitchMediaStreamAsyncCallback switch_media_stream
)
1168 ExternalDemuxer
*demuxer
;
1171 LOG_MEDIAELEMENT ("MediaElement::SetDemuxerSource (%p)\n", demuxer
);
1176 g_return_val_if_fail (context
!= NULL
, NULL
);
1177 g_return_val_if_fail (close_demuxer
!= NULL
&& get_diagnostic
!= NULL
&& get_sample
!= NULL
&& open_demuxer
!= NULL
&& seek
!= NULL
&& switch_media_stream
!= NULL
, NULL
);
1178 g_return_val_if_fail (playlist
== NULL
, NULL
);
1180 flags
|= Initializing
;
1183 media
= new Media (playlist
);
1184 demuxer
= new ExternalDemuxer (media
, context
, close_demuxer
, get_diagnostic
, get_sample
, open_demuxer
, seek
, switch_media_stream
);
1185 playlist
->GetCurrentEntry ()->InitializeWithDemuxer (demuxer
);
1188 SetDownloadProgress (1.0);
1190 flags
&= ~Initializing
;
1196 MediaElement::SetPlayRequested ()
1198 LOG_MEDIAELEMENT ("MediaElement::SetPlayRequested ()\n");
1201 flags
|= PlayRequested
;
1205 MediaElement::PlayOrStop ()
1207 LOG_MEDIAELEMENT ("MediaElement::PlayOrPause (): GetCanPause (): %s, PlayRequested: %s, GetAutoPlay: %s, AutoPlayed: %s\n",
1208 GetCanPause () ? "true" : "false", (flags
& PlayRequested
) ? "true" : "false",
1209 GetAutoPlay () ? "true" : "false", (flags
& AutoPlayed
) ? "true" : "false");
1212 if (!GetCanPause ()) {
1213 // If we can't pause, we play
1214 SetState (MediaStatePlaying
);
1215 playlist
->PlayAsync ();
1216 } else if (flags
& PlayRequested
) {
1217 // A Play has already been requested.
1218 SetState (MediaStatePlaying
);
1219 playlist
->PlayAsync ();
1220 } else if (GetAutoPlay () && !(flags
& AutoPlayed
)) {
1222 flags
|= AutoPlayed
;
1223 SetState (MediaStatePlaying
);
1224 playlist
->PlayAsync ();
1226 SetState (MediaStatePaused
);
1231 MediaElement::Pause ()
1233 LOG_MEDIAELEMENT ("MediaElement::Pause (): current state: %s\n", GetStateName (state
));
1236 if (playlist
== NULL
)
1240 case MediaStateOpening
:// docs: No specified behaviour
1241 flags
&= ~PlayRequested
;
1243 case MediaStateClosed
: // docs: No specified behaviour
1245 case MediaStatePaused
:// docs: no-op
1246 case MediaStateBuffering
:
1247 case MediaStatePlaying
:
1248 case MediaStateStopped
: // docs: pause
1249 paused_position
= GetPosition ();
1250 SetState (MediaStatePaused
);
1251 playlist
->PauseAsync ();
1253 case MediaStateIndividualizing
:
1254 case MediaStateAcquiringLicense
:
1255 g_warning ("MediaElement: Invalid state.");
1261 MediaElement::Play ()
1263 LOG_MEDIAELEMENT ("MediaElement::Play (): current state: %s\n", GetStateName (state
));
1266 g_return_if_fail (playlist
!= NULL
);
1269 case MediaStateClosed
: // docs: No specified behaviour
1270 case MediaStateOpening
:// docs: No specified behaviour
1271 flags
|= PlayRequested
;
1273 case MediaStatePlaying
:// docs: no-op
1274 case MediaStateBuffering
:
1275 case MediaStatePaused
:
1276 case MediaStateStopped
:
1277 SetState (MediaStatePlaying
);
1278 playlist
->PlayAsync ();
1280 case MediaStateIndividualizing
:
1281 case MediaStateAcquiringLicense
:
1282 g_warning ("MediaElement: Invalid state.");
1288 MediaElement::Stop ()
1290 LOG_MEDIAELEMENT ("MediaElement::Stop (): current state: %s\n", GetStateName (state
));
1293 if (GetSurface () == NULL
)
1297 case MediaStateOpening
:// docs: No specified behaviour
1298 flags
&= ~PlayRequested
;
1300 case MediaStateClosed
: // docs: No specified behaviour
1301 case MediaStateStopped
:// docs: no-op
1303 case MediaStateBuffering
:
1304 case MediaStatePlaying
:
1305 case MediaStatePaused
: // docs: stop
1306 flags
&= ~PlayRequested
;
1308 LOG_MEDIAELEMENT ("MediaElement::Stop (): state: %s, IsSingleFile: %i\n", GetStateName (state
), playlist
->IsSingleFile ());
1310 if (!playlist
->IsSingleFile ())
1311 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).
1313 SetState (MediaStateStopped
);
1314 playlist
->StopAsync ();
1316 case MediaStateIndividualizing
:
1317 case MediaStateAcquiringLicense
:
1318 g_warning ("MediaElement: Invalid state.");
1324 MediaElement::Seek (TimeSpan to
, bool force
)
1326 LOG_MEDIAELEMENT ("MediaElement::Seek (%" G_GUINT64_FORMAT
" = %" G_GUINT64_FORMAT
" ms)\n", to
, MilliSeconds_FromPts (to
));
1329 if (GetSurface () == NULL
)
1332 if (!force
&& !GetCanSeek ()) {
1333 LOG_MEDIAELEMENT ("MediaElement::Seek (): CanSeek is false, not seeking\n");
1338 case MediaStateIndividualizing
:
1339 case MediaStateAcquiringLicense
:
1340 g_warning ("MediaElement:Seek (): Invalid state %s\n", GetStateName (state
));
1342 case MediaStateOpening
:
1343 case MediaStateClosed
:
1347 case MediaStateBuffering
:
1348 case MediaStatePlaying
:
1349 case MediaStatePaused
:
1350 case MediaStateStopped
:
1351 Duration
*duration
= GetNaturalDuration ();
1353 if (duration
->HasTimeSpan () && to
> duration
->GetTimeSpan ())
1354 to
= duration
->GetTimeSpan ();
1358 if (!force
&& to
== TimeSpan_FromPts (mplayer
->GetPosition ()))
1361 previous_position
= to
;
1362 seek_to_position
= to
;
1363 seeked_to_position
= to
;
1364 paused_position
= to
;
1366 mplayer
->NotifySeek (TimeSpan_ToPts (to
));
1367 playlist
->SeekAsync (to
);
1368 Emit (MediaInvalidatedEvent
);
1371 LOG_MEDIAELEMENT ("MediaElement::Seek (%" G_GUINT64_FORMAT
" = %" G_GUINT64_FORMAT
" ms) previous position: %" G_GUINT64_FORMAT
"\n", to
, MilliSeconds_FromPts (to
), previous_position
);
1378 MediaElement::OnPropertyChanged (PropertyChangedEventArgs
*args
, MoonError
*error
)
1380 if (args
->GetId () == MediaElement::SourceProperty
) {
1381 DownloaderAccessPolicy policy
= MediaPolicy
;
1382 Uri
*uri
= GetSource ();
1383 const char *location
;
1386 if (!(location
= GetDeployment ()->GetXapLocation ()) && GetSurface ())
1387 location
= GetSurface ()->GetSourceLocation ();
1389 if (uri
->scheme
&& (!strcmp (uri
->scheme
, "mms") || !strcmp (uri
->scheme
, "rtsp") || !strcmp (uri
->scheme
, "rtsps")))
1390 policy
= StreamingPolicy
;
1392 if (uri
->IsInvalidPath ()) {
1393 EmitAsync (MediaFailedEvent
, new ErrorEventArgs (MediaError
, MoonError (MoonError::ARGUMENT_OUT_OF_RANGE
, 0, "invalid path found in uri")));
1395 } else if (!Downloader::ValidateDownloadPolicy (location
, uri
, policy
)) {
1396 EmitAsync (MediaFailedEvent
, new ErrorEventArgs (MediaError
, MoonError (MoonError::ARGUMENT_OUT_OF_RANGE
, 0, "Security Policy Violation")));
1401 flags
|= RecalculateMatrix
;
1403 } else if (args
->GetId () == MediaElement::AudioStreamIndexProperty
) {
1405 mplayer
->SetAudioStreamIndex (args
->GetNewValue()->AsInt32 ());
1406 } else if (args
->GetId () == MediaElement::AutoPlayProperty
) {
1407 // no state to change
1408 } else if (args
->GetId () == MediaElement::BalanceProperty
) {
1410 mplayer
->SetBalance (args
->GetNewValue()->AsDouble ());
1411 } else if (args
->GetId () == MediaElement::BufferingProgressProperty
) {
1412 // read-only property
1413 } else if (args
->GetId () == MediaElement::BufferingTimeProperty
) {
1415 // Not quite sure what to do here, we could:
1416 // a) store the buffering time on the mediaplayer and let the media request it whenever it needs it
1417 // b) let the media request the buffering time from mediaelement
1418 // 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)
1419 // note that thread-safety is easier with a) (media will do the request from another thread) or c)
1422 media->SetBufferingTime (TimeSpan_ToPts (GetBufferingTime ()));
1424 } else if (args
->GetId () == MediaElement::CurrentStateProperty
) {
1425 // read-only property
1426 // This should really not happen, we use a property provider for this property.
1427 } else if (args
->GetId () == MediaElement::IsMutedProperty
) {
1429 mplayer
->SetMuted (args
->GetNewValue()->AsBool ());
1430 } else if (args
->GetId () == MediaElement::MarkersProperty
) {
1432 } else if (args
->GetId () == MediaElement::NaturalVideoHeightProperty
) {
1433 // read-only property
1434 flags
|= RecalculateMatrix
;
1435 } else if (args
->GetId () == MediaElement::NaturalVideoWidthProperty
) {
1436 // read-only property
1437 flags
|= RecalculateMatrix
;
1438 } else if (args
->GetId () == MediaElement::PositionProperty
) {
1439 Seek (args
->GetNewValue()->AsTimeSpan (), false);
1440 ClearValue (MediaElement::PositionProperty
, false); // We need this, otherwise our property system will return the seeked-to position forever (MediaElementPropertyValueProvider isn't called).
1441 } else if (args
->GetId () == MediaElement::VolumeProperty
) {
1443 mplayer
->SetVolume (args
->GetNewValue()->AsDouble ());
1446 if (args
->GetProperty ()->GetOwnerType() != Type::MEDIAELEMENT
) {
1447 // propagate to parent class
1448 FrameworkElement::OnPropertyChanged (args
, error
);
1449 flags
|= RecalculateMatrix
;
1453 NotifyListenersOfPropertyChange (args
, error
);
1457 MediaElement::EnableAntiAlias (void)
1459 return !(absolute_xform
.xx
== absolute_xform
.yy
&& /* no rotation */
1460 (absolute_xform
.yx
== 0 && absolute_xform
.xy
== 0)); /* no skew */
1465 MediaElement::ReportErrorOccurredCallback (EventObject
*obj
)
1467 MediaElement
*me
= (MediaElement
*) obj
;
1468 ErrorEventArgs
*args
;
1471 args
= me
->error_args
;
1472 me
->error_args
= NULL
;
1473 me
->mutex
.Unlock ();
1475 me
->ReportErrorOccurred (args
);
1481 MediaElement::ReportErrorOccurred (ErrorEventArgs
*args
)
1483 LOG_MEDIAELEMENT ("MediaElement::ReportErrorOccurred (%p)\n", args
);
1485 if (!Surface::InMainThread ()) {
1488 error_args
->unref ();
1493 AddTickCallSafe (ReportErrorOccurredCallback
);
1498 MediaErrorHandler (NULL
, args
);
1502 MediaElement::ReportErrorOccurred (const char *args
)
1504 LOG_MEDIAELEMENT ("MediaElement::ReportErrorOccurred ('%s')\n", args
);
1506 ErrorEventArgs
*eea
= new ErrorEventArgs (MediaError
, MoonError (MoonError::EXCEPTION
, 3001, g_strdup (args
)));
1507 ReportErrorOccurred (eea
);
1512 * MediaElementPropertyValueProvider
1515 MediaElementPropertyValueProvider::MediaElementPropertyValueProvider (MediaElement
*element
, PropertyPrecedence precedence
)
1516 : FrameworkElementProvider (element
, precedence
)
1519 current_state
= NULL
;
1520 rendered_frames_per_second
= NULL
;
1521 dropped_frames_per_second
= NULL
;
1524 MediaElementPropertyValueProvider::~MediaElementPropertyValueProvider ()
1527 delete current_state
;
1528 delete rendered_frames_per_second
;
1529 delete dropped_frames_per_second
;
1533 MediaElementPropertyValueProvider::GetPropertyValue (DependencyProperty
*property
)
1535 // We verify main thread here too in case some object in the pipeline happens to want a property on the media element
1538 if (property
->GetId () == MediaElement::PositionProperty
)
1539 return GetPosition ();
1541 if (property
->GetId () == MediaElement::CurrentStateProperty
)
1542 return GetCurrentState ();
1544 if (property
->GetId () == MediaElement::DroppedFramesPerSecondProperty
)
1545 return GetDroppedFramesPerSecond ();
1547 if (property
->GetId () == MediaElement::RenderedFramesPerSecondProperty
)
1548 return GetRenderedFramesPerSecond ();
1550 return FrameworkElementProvider::GetPropertyValue (property
);
1554 MediaElementPropertyValueProvider::GetDroppedFramesPerSecond ()
1556 MediaElement
*element
= (MediaElement
*) obj
;
1557 MediaPlayer
*mplayer
= element
->GetMediaPlayer ();
1559 delete dropped_frames_per_second
;
1562 dropped_frames_per_second
= new Value (mplayer
->GetDroppedFramesPerSecond ());
1564 dropped_frames_per_second
= NULL
;
1567 return dropped_frames_per_second
;
1571 MediaElementPropertyValueProvider::GetRenderedFramesPerSecond ()
1573 MediaElement
*element
= (MediaElement
*) obj
;
1574 MediaPlayer
*mplayer
= element
->GetMediaPlayer ();
1576 delete rendered_frames_per_second
;
1579 rendered_frames_per_second
= new Value (mplayer
->GetRenderedFramesPerSecond ());
1581 rendered_frames_per_second
= NULL
;
1584 return rendered_frames_per_second
;
1588 MediaElementPropertyValueProvider::GetCurrentState ()
1590 MediaElement
*element
= (MediaElement
*) obj
;
1592 delete current_state
;
1593 current_state
= new Value (element
->state
);
1595 return current_state
;
1599 MediaElementPropertyValueProvider::GetPosition ()
1601 bool use_mplayer
= false;;
1602 bool use_pause
= false;
1603 MediaElement
*element
= (MediaElement
*) obj
;
1604 guint64 position
= TimeSpan_ToPts (element
->seek_to_position
);
1606 delete this->position
;
1607 this->position
= NULL
;
1609 switch (element
->state
) {
1610 case MediaStateIndividualizing
:
1611 case MediaStateAcquiringLicense
:
1612 g_warning ("MediaElementPropertyValueProvider::GetPosition (): Invalid state.\n");
1614 case MediaStateOpening
:
1615 case MediaStateClosed
:
1616 use_mplayer
= false;
1618 case MediaStateStopped
:
1621 case MediaStateBuffering
:
1622 case MediaStatePlaying
:
1625 case MediaStatePaused
:
1630 // If a seek is pending, we need to return that position.
1632 if (TimeSpan_FromPts (position
) == -1)
1633 position
= element
->mplayer
->GetPosition ();
1634 } else if (use_pause
) {
1635 position
= element
->paused_position
;
1638 if (position
< element
->seeked_to_position
)
1639 position
= element
->seeked_to_position
;
1641 if (TimeSpan_FromPts (position
) == -1) {
1644 position
= MIN (position
, element
->mplayer
->GetDuration ());
1647 this->position
= new Value (TimeSpan_FromPts (position
), Type::TIMESPAN
);
1648 return this->position
;