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, 2008 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
18 #include "timesource.h"
19 #include "timemanager.h"
20 #include "mediaplayer.h"
25 #include "mediaelement.h"
29 #define DEBUG_ADVANCEFRAME 0
35 MediaPlayer::MediaPlayer (MediaElement
*el
)
36 : EventObject (Type::MEDIAPLAYER
)
38 LOG_MEDIAPLAYER ("MediaPlayer::MediaPlayer (%p, id=%i), id=%i\n", el
, GET_OBJ_ID (el
), GET_OBJ_ID (this));
49 format
= MoonPixelFormatRGB32
;
50 advance_frame_timeout_id
= 0;
53 audio_unlocked
= NULL
;
58 MediaPlayer::~MediaPlayer ()
60 LOG_MEDIAPLAYER ("MediaPlayer::~MediaPlayer (), id=%i\n", GET_OBJ_ID (this));
65 MediaPlayer::Dispose ()
67 LOG_MEDIAPLAYER ("MediaPlayer::Dispose (), id=%i\n", GET_OBJ_ID (this));
75 EventObject::Dispose ();
79 MediaPlayer::GetAudio ()
81 AudioSource
*result
= NULL
;
86 if (audio_unlocked
!= NULL
) {
87 result
= audio_unlocked
;
96 MediaPlayer::SetSurface (Surface
*s
)
98 if (!SetSurfaceLock ())
101 EventObject::SetSurface (s
);
107 MediaPlayer::AudioFinishedCallback (EventObject
*user_data
)
109 LOG_MEDIAPLAYER ("MediaPlayer::AudioFinishedCallback ()\n");
112 MediaPlayer
*mplayer
= (MediaPlayer
*) user_data
;
113 mplayer
->AudioFinished ();
117 MediaPlayer::AudioFinished ()
119 LOG_MEDIAPLAYER ("MediaPlayer::AudioFinished () VideoEnded: %i, AudioEnded: %i AudioSource id: %i\n", GetBit (VideoEnded
), GetBit (AudioEnded
), GET_OBJ_ID (audio_unlocked
));
121 // This method must be thread-safe
123 if (!Surface::InMainThread ()) {
124 AddTickCallSafe (AudioFinishedCallback
);
129 if (!GetBit (AudioEnded
)) {
136 MediaPlayer::VideoFinished ()
138 LOG_MEDIAPLAYER ("MediaPlayer::VideoFinished () VideoEnded: %i, AudioEnded: %i\n", GetBit (VideoEnded
), GetBit (AudioEnded
));
141 if (!GetBit (VideoEnded
)) {
148 MediaPlayer::CheckFinished ()
150 LOG_MEDIAPLAYER ("MediaPlayer::CheckFinished (), HasVideo: %i, VideoEnded: %i, HasAudio: %i, AudioEnded: %i\n",
151 HasVideo (), GetBit (VideoEnded
), HasAudio (), GetBit (AudioEnded
));
154 if (HasVideo () && !GetBit (VideoEnded
))
157 if (HasAudio () && !GetBit (AudioEnded
))
160 Emit (MediaEndedEvent
);
164 MediaPlayer::AudioFailed (AudioSource
*source
)
166 // This method must be thread-safe
169 if (this->audio_unlocked
== source
) {
170 AudioPlayer::Remove (this->audio_unlocked
);
171 this->audio_unlocked
->unref ();
172 this->audio_unlocked
= NULL
;
178 MediaPlayer::Open (Media
*media
, PlaylistEntry
*entry
)
180 IMediaDecoder
*encoding
;
181 IMediaStream
*stream
;
182 guint64 asx_duration
;
183 gint32
*audio_stream_index
= NULL
;
186 LOG_MEDIAPLAYER ("MediaPlayer::Open (%p), current media: %p\n", media
, this->media
);
192 printf ("MediaPlayer::Open (): media is NULL.\n");
196 if (!media
->IsOpened ()) {
197 printf ("MediaPlayer::Open (): media isn't opened.\n");
206 // Find audio/video streams
207 IMediaDemuxer
*demuxer
= media
->GetDemuxer ();
208 VideoStream
*vstream
= NULL
;
209 AudioStream
*astream
= NULL
, *astream2
= NULL
;
211 if (demuxer
== NULL
) {
212 fprintf (stderr
, "MediaPlayer::Open (): media doesn't have a demuxer.\n");
216 audio_stream_index
= element
->GetAudioStreamIndex ();
218 for (int i
= 0; i
< demuxer
->GetStreamCount (); i
++) {
219 stream
= demuxer
->GetStream (i
);
220 encoding
= stream
->GetDecoder (); //stream->codec;
222 if (encoding
== NULL
)
223 continue; // No encoding was found for the stream.
225 switch (stream
->GetType ()) {
227 audio_stream_count
++;
228 if (audio_stream_index
!= NULL
){
229 if (*audio_stream_index
== audio_stream_count
- 1) {
230 astream
= (AudioStream
*) stream
;
233 astream2
= (AudioStream
*) stream
;
235 if (astream
== NULL
|| astream
->GetBitRate () < astream2
->GetBitRate ())
241 vstream
= (VideoStream
*) stream
;
243 if (video_stream
!= NULL
&& vstream
->GetBitRate () < video_stream
->GetBitRate ())
246 video_stream
= vstream
;
247 video_stream
->SetSelected (true);
248 video_stream
->ref ();
250 height
= video_stream
->height
;
251 width
= video_stream
->width
;
253 SetVideoBufferSize (width
, height
);
255 // printf ("video size: %i, %i\n", video_stream->width, video_stream->height);
257 case MediaTypeMarker
:
258 LOG_MEDIAPLAYER ("MediaPlayer::Open (): Found a marker stream, selecting it.\n");
259 stream
->SetSelected (true);
265 if (astream
!= NULL
) {
266 audio
= AudioPlayer::Add (this, astream
);
268 // Only select the audio stream if we can actually play it
269 astream
->SetSelected (true);
271 LOG_MEDIAPLAYER ("MediaPlayer::Open(): Selected audio stream (%d) properties:\n"
272 "\tchannels: Input: %d Output: %d\n"
273 "\tsample_rate: Input: %d Output: %d\n"
274 "\tbit_rate: Input: %d Output: %d\n"
275 "\tblock_align: Input: %d Output: %d\n"
276 "\tbits_per_sample: Input: %d Output: %d\n"
278 "\tduration: %" G_GUINT64_FORMAT
"\n"
279 "\textra data size: %d\n",
280 astream
->index
, astream
->GetChannels (), astream
->GetOutputChannels (),
281 astream
->GetSampleRate (), astream
->GetOutputSampleRate (),
282 astream
->GetBitRate (), astream
->GetOutputBitRate (),
283 astream
->GetBlockAlign (), astream
->GetOutputBlockAlign (),
284 astream
->GetBitsPerSample (), astream
->GetOutputBitsPerSample (),
285 astream
->GetCodecId (), astream
->GetDuration (), astream
->GetExtraDataSize ());
286 if (astream
->extra_data_size
> 0) {
288 LOG_MEDIAPLAYER ("\textra data: ");
289 for (n
= 0; n
< astream
->extra_data_size
; n
++)
290 LOG_MEDIAPLAYER ("[0x%x] ", ((gint8
*)astream
->extra_data
)[n
]);
291 LOG_MEDIAPLAYER ("\n");
294 this->audio_unlocked
= audio
;
298 if (video_stream
!= NULL
) {
299 LOG_MEDIAPLAYER ("MediaPlayer::Open(): Selected Video stream (%d) properties:\n"
302 "\tbits_per_sample: %d\n"
305 "\tpts_per_frame: %" G_GUINT64_FORMAT
"\n"
306 "\tduration: %" G_GUINT64_FORMAT
"\n"
307 "\textra data size: %d\n",
308 video_stream
->index
, video_stream
->width
, video_stream
->height
, video_stream
->bits_per_sample
,
309 video_stream
->bit_rate
, video_stream
->codec_id
, video_stream
->pts_per_frame
,
310 video_stream
->duration
, video_stream
->extra_data_size
);
311 if (video_stream
->extra_data_size
> 0) {
313 LOG_MEDIAPLAYER ("\textra data: ");
314 for (n
= 0; n
< video_stream
->extra_data_size
; n
++)
315 LOG_MEDIAPLAYER ("[0x%x] ", ((gint8
*)video_stream
->extra_data
)[n
]);
316 LOG_MEDIAPLAYER ("\n");
325 start_pts
= TimeSpan_ToPts (entry
->GetStartTime ());
326 LOG_MEDIAPLAYER ("MediaPlayer::Open (), setting start_pts to: %" G_GUINT64_FORMAT
" (%" G_GUINT64_FORMAT
" ms).\n", start_pts
, MilliSeconds_FromPts (start_pts
));
328 printf ("TODO: Seek to start pts\n");
329 // SeekInternal (start_pts);
332 if (entry
->GetIsLive ())
336 duration
= media
->GetDemuxer ()->GetDuration ();
338 if (entry
!= NULL
&& entry
->HasInheritedDuration () && entry
->GetInheritedDuration ()->HasTimeSpan ()) {
339 asx_duration
= TimeSpan_ToPts (entry
->GetInheritedDuration ()->GetTimeSpan ());
340 if (asx_duration
< duration
|| GetBit (IsLive
)) {
341 duration
= asx_duration
;
342 SetBit (FixedDuration
);
346 SetBit (LoadFramePending
);
348 media
->AddSafeHandler (Media::SeekCompletedEvent
, SeekCompletedCallback
, this);
349 media
->SetBufferingTime (element
->GetBufferingTime ());
352 video_stream
->AddSafeHandler (IMediaStream::FirstFrameEnqueuedEvent
, FirstFrameEnqueuedCallback
, this);
353 // We may attach the handler above after the first frame has been queued,
354 // so just execute LoadVideoFrame once right away
362 MediaPlayer::SetVideoBufferSize (gint32 width
, gint32 height
)
366 LOG_MEDIAPLAYER ("MediaPlayer::SetVideoBufferSize (%i, %i). buffer_width: %i, buffer_height: %i\n", width
, height
, buffer_width
, buffer_height
);
370 cairo_surface_destroy (surface
);
374 /* NOTE: We only accept RGB32 or RGBA32 data here */
375 stride
= cairo_format_stride_for_width (format
== MoonPixelFormatRGB32
? CAIRO_FORMAT_RGB24
: CAIRO_FORMAT_ARGB32
, MAX (width
, buffer_width
));
378 int remain
= stride
% 64;
379 stride
+= 64 - remain
;
382 if (width
> buffer_width
|| height
> buffer_height
) {
383 LOG_MEDIAPLAYER ("MediaPlayer::SetVideoBufferSize (): creating new buffer.\n");
385 // for conversion to rgb32 format needed for rendering with 16 byte alignment
386 if (posix_memalign ((void **)(&rgb_buffer
), 16, height
* stride
)) {
388 g_warning ("Could not allocate memory for video RGB buffer");
391 memset (rgb_buffer
, 0, height
* stride
);
393 buffer_width
= width
;
394 buffer_height
= height
;
398 LOG_MEDIAPLAYER ("MediaPlayer::SetVideoBufferSize (): creating new surface, width: %i, height: %i, stride: %i\n", width
, height
, stride
);
399 /* NOTE: We only accept RGB32 or RGBA32 data here */
400 surface
= cairo_image_surface_create_for_data (rgb_buffer
, format
== MoonPixelFormatRGB32
? CAIRO_FORMAT_RGB24
: CAIRO_FORMAT_ARGB32
, width
, height
, stride
);
404 MediaPlayer::Initialize ()
406 LOG_MEDIAPLAYER ("MediaPlayer::Initialize ()\n");
409 // Clear out any state, bits, etc
410 state_unlocked
= (PlayerState
) 0;
411 // Set initial states and bits
413 SetBit (SeekSynched
);
421 first_live_pts
= G_MAXUINT64
;
423 audio_stream_count
= 0;
427 frames_update_timestamp
= 0;
430 rendered_frames_per_second
= 0.0;
431 dropped_frames_per_second
= 0.0;
435 MediaPlayer::Close ()
437 LOG_MEDIAPLAYER ("MediaPlayer::Close ()\n");
441 if (audio_unlocked
) {
442 AudioPlayer::Remove (audio_unlocked
);
443 audio_unlocked
->Dispose ();
444 audio_unlocked
->unref ();
445 audio_unlocked
= NULL
;
451 // Reset state back to what it was at instantiation
453 if (rgb_buffer
!= NULL
) {
460 if (surface
!= NULL
) {
461 cairo_surface_destroy (surface
);
466 video_stream
->RemoveSafeHandlers (this);
467 video_stream
->unref ();
480 // Puts the data into our rgb buffer.
481 // If necessary converts the data from its source format to rgb first.
485 MediaPlayer::RenderFrame (MediaFrame
*frame
)
487 VideoStream
*stream
= (VideoStream
*) frame
->stream
;
489 LOG_MEDIAPLAYER_EX ("MediaPlayer::RenderFrame (%p), pts: %" G_GUINT64_FORMAT
" ms, buflen: %i, buffer: %p, IsPlanar: %i\n", frame
, MilliSeconds_FromPts (frame
->pts
), frame
->buflen
, frame
->buffer
, frame
->IsPlanar ());
492 if (!frame
->IsDecoded ()) {
493 fprintf (stderr
, "MediaPlayer::RenderFrame (): Trying to render a frame which hasn't been decoded yet.\n");
497 if ((frame
->width
> 0 && frame
->width
!= width
) || (frame
->height
> 0 && frame
->height
!= height
) || (format
!= stream
->GetDecoder ()->GetPixelFormat ())) {
498 LOG_MEDIAPLAYER ("MediaPlayer::RenderFrame () frame width: %i, frame height: %i, stream width: %i, stream height: %i, previous frame width: %i, previous frame height: %i\n",
499 frame
->width
, frame
->height
, video_stream
->width
, video_stream
->height
, width
, height
);
501 if (frame
->width
> 0)
502 width
= frame
->width
;
503 if (frame
->height
> 0)
504 height
= frame
->height
;
506 format
= stream
->GetDecoder ()->GetPixelFormat ();
508 SetVideoBufferSize (width
, height
);
511 if (!frame
->IsPlanar ()) {
512 // Just copy the data
513 guint32 stride
= cairo_image_surface_get_stride (surface
);
514 for (int i
= 0; i
< height
; i
++)
515 memcpy (rgb_buffer
+ stride
* i
, frame
->buffer
+ i
* width
* 4, width
* 4);
516 SetBit (RenderedFrame
);
517 element
->MediaInvalidate ();
521 if (frame
->data_stride
== NULL
||
522 frame
->data_stride
[1] == NULL
||
523 frame
->data_stride
[2] == NULL
) {
527 guint8
*rgb_dest
[3] = { rgb_buffer
, NULL
, NULL
};
528 int rgb_stride
[3] = { cairo_image_surface_get_stride (surface
), 0, 0 };
530 stream
->converter
->Convert (frame
->data_stride
, frame
->srcStride
, frame
->srcSlideY
,
531 frame
->srcSlideH
, rgb_dest
, rgb_stride
);
533 SetBit (RenderedFrame
);
534 element
->MediaInvalidate ();
538 printf ("MediaPlayer::AdvanceFrame (), %10s frame pts: %6llu ms, target pts: %6llu ms, diff: %+5lld, rendered fps: %5.2f, dropped fps: %5.2f, total: %5.2f\n", x, \
539 MilliSeconds_FromPts (frame->pts), \
540 MilliSeconds_FromPts (target_pts), \
541 (gint64) MilliSeconds_FromPts (frame->pts) - (gint64) MilliSeconds_FromPts (target_pts), \
542 rendered_frames_per_second, \
543 dropped_frames_per_second, \
544 dropped_frames_per_second + rendered_frames_per_second);
547 MediaPlayer::AdvanceFrame ()
549 MediaFrame
*frame
= NULL
;
550 IMediaStream
*stream
;
551 guint64 target_pts
= 0;
552 guint64 target_pts_start
= 0;
553 guint64 target_pts_end
= 0;
554 guint64 target_pts_delta
= MilliSeconds_ToPts (100);
556 double dropped_frames_per_second
= -1;
557 double rendered_frames_per_second
= -1;
562 LOG_MEDIAPLAYER_EX ("MediaPlayer::AdvanceFrame () state: %i, current_pts = %" G_GUINT64_FORMAT
", IsPaused: %i, IsSeeking: %i, VideoEnded: %i, AudioEnded: %i, HasVideo: %i, HasAudio: %i\n",
563 state_unlocked
, current_pts
, IsPaused (), IsSeeking (), GetBit (VideoEnded
), GetBit (AudioEnded
), HasVideo (), HasAudio ());
566 RemoveBit (LoadFramePending
);
574 if (GetBit (VideoEnded
))
580 // If the audio isn't playing, there might be slight length-difference between
581 // audio and video streams (the audio is shorted and finished earlier for instance)
582 // Treat this case as if there's no audio at all.
584 if (audio
!= NULL
&& audio
->GetState () == AudioPlaying
) {
585 // use target_pts as set by audio thread
586 target_pts
= GetTargetPts ();
587 if (target_pts
== G_MAXUINT64
) {
588 // This might happen if we've called Play on the audio source, but it hasn't actually played anything yet.
589 LOG_MEDIAPLAYER_EX ("MediaPlayer::AdvanceFrame (): invalid target pts from the audio stream.\n");
594 // no audio to sync to
595 guint64 now
= TimeSpan_ToPts (element
->GetTimeManager()->GetCurrentTime ());
596 guint64 elapsed_pts
= now
- start_time
;
598 target_pts
= elapsed_pts
;
601 printf ("MediaPlayer::AdvanceFrame (): determined target_pts to be: %" G_GUINT64_FORMAT " = %" G_GUINT64_FORMAT " ms, elapsed_pts: %llu = %llu ms, start_time: %llu = %llu ms\n",
602 target_pts, MilliSeconds_FromPts (target_pts), elapsed_pts, MilliSeconds_FromPts (elapsed_pts), start_time, MilliSeconds_FromPts (start_time));
610 this->target_pts
= target_pts
;
612 target_pts_start
= target_pts_delta
> target_pts
? 0 : target_pts
- target_pts_delta
;
613 target_pts_end
= target_pts
+ target_pts_delta
;
615 if (current_pts
>= target_pts_end
&& GetBit (SeekSynched
) && !(HasAudio () && GetBit (AudioEnded
))) {
616 #if DEBUG_ADVANCEFRAME
617 printf ("MediaPlayer::AdvanceFrame (): video is running too fast, wait a bit (current_pts: %" G_GUINT64_FORMAT
" ms, target_pts: %" G_GUINT64_FORMAT
" ms, delta: %llu ms, diff: %lld (%lld ms)).\n",
618 MilliSeconds_FromPts (current_pts
), MilliSeconds_FromPts (target_pts
), MilliSeconds_FromPts (target_pts_delta
), current_pts
- target_pts
, MilliSeconds_FromPts (current_pts
- target_pts
));
623 #if DEBUG_ADVANCEFRAME
624 printf ("MediaPlayer::AdvanceFrame (): target pts: %" G_GUINT64_FORMAT
" = %" G_GUINT64_FORMAT
" ms\n", target_pts
, MilliSeconds_FromPts (target_pts
));
628 frame
= video_stream
->PopFrame ();
630 if (video_stream
->GetOutputEnded ()) {
632 // Set the target pts to the last pts we showed, since target_pts is what's reported as our current position.
633 this->target_pts
= current_pts
;
639 SetBufferUnderflow ();
640 // If we have audio, we keep playing (and loosing frames) until the audio playing stops due to buffer underflow
641 // TODO: determine if we don't have video due to not having enough data (in which case we should start buffering),
642 // or if it is because the decoder can't keep up (in which case we should drop frames).
646 stream
= frame
->stream
;
647 current_pts
= frame
->pts
;
650 //printf ("MediaPlayer::AdvanceFrame (): current_pts: %" G_GUINT64_FORMAT " = %" G_GUINT64_FORMAT " ms, duration: %llu = %llu ms\n",
651 // current_pts, MilliSeconds_FromPts (current_pts),
652 // duration, MilliSeconds_FromPts (duration));
654 if (GetBit (IsLive
)) {
655 first_live_pts
= MIN (current_pts
, first_live_pts
);
658 if (GetBit (FixedDuration
)) {
660 printf ("MediaPlayer::AdvanceFrame (): (fixed duration, live: %i) current_pts: %" G_GUINT64_FORMAT " ms, duration: %" G_GUINT64_FORMAT " ms, first_live_pts: %" G_GUINT64_FORMAT " ms, diff: %" G_GUINT64_FORMAT "ms\n",
661 GetBit (IsLive), MilliSeconds_FromPts (current_pts), MilliSeconds_FromPts (duration), MilliSeconds_FromPts (first_live_pts), MilliSeconds_FromPts (current_pts - first_live_pts));
663 if (GetBit (IsLive
)) {
664 if (current_pts
- first_live_pts
> duration
) {
665 // TODO: Move this out of AdvanceFrame, here it only works for media which has video, not for audio-only media.
671 if (current_pts
> duration
) {
677 if (GetBit (VideoEnded
)) {
678 //printf ("MediaPlayer::AdvanceFrame (): Reached end of duration.\n");
684 if (!frame
->IsDecoded ()) {
685 printf ("MediaPlayer::AdvanceFrame (): Got a non-decoded frame.\n");
689 if (update
&& current_pts
>= target_pts_start
) {
690 if (!GetBit (SeekSynched
)) {
691 SetBit (SeekSynched
);
692 LOG_MEDIAPLAYER ("MediaPlayer::AdvanceFrame (): We have now successfully synched with the audio after the seek, current_pts: %" G_GUINT64_FORMAT
", target_pts_start: %" G_GUINT64_FORMAT
"\n", MilliSeconds_FromPts (current_pts
), MilliSeconds_FromPts (target_pts_start
));
694 // we are in sync (or ahead) of audio playback
698 if (video_stream
->IsQueueEmpty ()) {
699 // no more packets in queue, this frame is the most recent we have available
703 // we are lagging behind, drop this frame
706 //LOG_RS ("[SKIPPED]");
707 media
->DisposeObject (frame
);
712 if (update
&& frame
&& GetBit (SeekSynched
)) {
714 //LOG_RS ("[RENDER]");
720 media
->DisposeObject (frame
);
726 if (frames_update_timestamp
== 0) {
727 frames_update_timestamp
= now
;
728 } else if ((now
- frames_update_timestamp
) > TIMESPANTICKS_IN_SECOND
) {
729 double time_elapsed
= (double) (now
- frames_update_timestamp
) / (double) TIMESPANTICKS_IN_SECOND
;
730 dropped_frames_per_second
= (double) dropped_frames
/ time_elapsed
;
731 rendered_frames_per_second
= (double) rendered_frames
/ time_elapsed
;
732 dropped_frames
= rendered_frames
= 0;
733 frames_update_timestamp
= now
;
735 this->dropped_frames_per_second
= dropped_frames_per_second
;
736 this->rendered_frames_per_second
= rendered_frames_per_second
;
743 MediaPlayer::FirstFrameEnqueuedHandler (EventObject
*sender
, EventArgs
*args
)
749 MediaPlayer::LoadVideoFrameCallback (EventObject
*object
)
751 ((MediaPlayer
*) object
)->LoadVideoFrame ();
755 MediaPlayer::LoadVideoFrame ()
760 LOG_MEDIAPLAYER ("MediaPlayer::LoadVideoFrame (), HasVideo: %i, LoadFramePending: %i\n", HasVideo (), state_unlocked
& LoadFramePending
);
766 if (!IsLoadFramePending ())
769 frame
= video_stream
->PopFrame ();
774 target_pts
= GetTargetPts ();
776 if (target_pts
== G_MAXUINT64
)
779 LOG_MEDIAPLAYER ("MediaPlayer::LoadVideoFrame (), packet pts: %" G_GUINT64_FORMAT
", target pts: %" G_GUINT64_FORMAT
", pts_per_frame: %" G_GUINT64_FORMAT
", buflen: %i\n", frame
->pts
, GetTargetPts (), video_stream
->pts_per_frame
, frame
->buflen
);
781 if (frame
->pts
+ video_stream
->pts_per_frame
>= target_pts
) {
782 LOG_MEDIAPLAYER ("MediaPlayer::LoadVideoFrame (): rendering.\n");
783 RemoveBit (LoadFramePending
);
785 element
->MediaInvalidate ();
787 AddTickCallSafe (LoadVideoFrameCallback
);
790 media
->DisposeObject (frame
);
797 MediaPlayer::AdvanceFrameCallback (void *user_data
)
799 MediaPlayer
*mplayer
= (MediaPlayer
*) user_data
;
800 mplayer
->SetCurrentDeployment ();
801 mplayer
->AdvanceFrame ();
803 Deployment::SetCurrent (NULL
);
809 MediaPlayer::SetTimeout (gint32 timeout
/* set to 0 to clear */)
811 TimeManager
*time_manager
= element
? element
->GetTimeManager () : NULL
;
812 bool clear
= timeout
== 0 || advance_frame_timeout_id
!= 0;
814 LOG_MEDIAPLAYER ("MediaPlayer::SetTimeout (%i) time_manager: %p id: %i\n", timeout
, time_manager
, GET_OBJ_ID (time_manager
));
816 if (clear
&& advance_frame_timeout_id
!= 0) {
817 if (time_manager
!= NULL
) {
818 time_manager
->RemoveTimeout (advance_frame_timeout_id
);
820 g_warning ("MediaPlayer::SetTimeout (): Could not clear timeout. Leaking ourselves to not crash.\n");
821 ref (); // This will prevent us from getting destroyed.
823 advance_frame_timeout_id
= 0;
827 if (time_manager
== NULL
) {
828 g_warning ("MediaPlayer::SetTimeout (): Could not set timeout (no time manager).\n");
830 advance_frame_timeout_id
= time_manager
->AddTimeout (MOON_PRIORITY_DEFAULT
, timeout
, AdvanceFrameCallback
, this);
840 LOG_MEDIAPLAYER ("MediaPlayer::Play (), state: %i, IsPlaying: %i, IsSeeking: %i\n", state_unlocked
, IsPlaying (), IsSeeking ());
847 RemoveBit (BufferUnderflow
);
848 start_time
= TimeSpan_ToPts (element
->GetTimeManager()->GetCurrentTime ());
849 start_time
-= target_pts
;
857 SetTimeout (GetTimeoutInterval ());
859 LOG_MEDIAPLAYER ("MediaPlayer::Play (), state: %i [Done]\n", state_unlocked
);
863 MediaPlayer::GetTimeoutInterval ()
865 gint32 result
; // ms between timeouts
866 guint64 pts_per_frame
= 0;
871 pts_per_frame
= video_stream
->pts_per_frame
;
872 // there are 10000 pts in a millisecond, anything less than that will result in 0 (and an endless loop)
873 if (pts_per_frame
< PTS_PER_MILLISECOND
|| pts_per_frame
>= (guint64
) G_MAXINT32
) {
874 // If the stream doesn't know its frame rate, use a default of 60 fps
875 result
= (gint32
) (1000.0 / 60.0);
877 result
= (gint32
) MilliSeconds_FromPts (pts_per_frame
);
883 LOG_MEDIAPLAYER ("MediaPlayer::GetTimeoutInterval (): %i ms between frames gives fps: %.1f, pts_per_frame: %" G_GUINT64_FORMAT
", exact fps: %f\n", result
, 1000.0 / result
, pts_per_frame
, TIMESPANTICKS_IN_SECOND
/ (double) pts_per_frame
);
889 MediaPlayer::SetAudioStreamIndex (gint32 index
)
891 IMediaDemuxer
*demuxer
= NULL
;
892 IMediaStream
*stream
= NULL
;
893 AudioStream
*next_stream
= NULL
;
894 AudioStream
*prev_stream
= NULL
;
895 gint32 audio_streams_found
= 0;
898 LOG_MEDIAPLAYER ("MediaPlayer::SetAudioStreamIndex (%i).\n", index
);
901 if (index
< 0 || index
>= audio_stream_count
) {
902 LOG_MEDIAPLAYER ("MediaPlayer::SetAudioStreamIndex (%i): Invalid audio stream index.\n", index
);
907 LOG_MEDIAPLAYER ("MediaPlayer::SetAudioStreamIndex (%i): No media.\n", index
);
913 LOG_MEDIAPLAYER ("MediaPlayer::SetAudioStreamIndex (%i): No audio source.\n", index
);
917 demuxer
= media
->GetDemuxer ();
919 if (demuxer
== NULL
) {
920 LOG_MEDIAPLAYER ("MediaPlayer::SetAudioStreamIndex (%i): Media doesn't have a demuxer.\n", index
);
924 prev_stream
= audio
->GetAudioStream ();
926 for (int i
= 0; i
< demuxer
->GetStreamCount (); i
++) {
927 stream
= demuxer
->GetStream (i
);
929 if (stream
->GetType () != MediaTypeAudio
)
932 if (audio_streams_found
== index
) {
933 next_stream
= (AudioStream
*) stream
;
937 audio_streams_found
++;
940 if (next_stream
!= NULL
) {
941 LOG_MEDIAPLAYER ("MediaPlayer::SetAudioStreamIndex (%i). Switched stream from #%i to #%i\n", index
, audio_streams_found
++, index
);
942 prev_stream
->SetSelected (false);
943 next_stream
->SetSelected (true);
944 audio
->SetAudioStream (next_stream
);
951 MediaPlayer::GetCanPause ()
953 // FIXME: should return false if it is streaming media
955 return GetBit (CanPause
);
959 MediaPlayer::SetCanPause (bool value
)
962 SetBitTo (CanPause
, value
);
966 MediaPlayer::Pause ()
970 LOG_MEDIAPLAYER ("MediaPlayer::Pause (), state: %i\n", state_unlocked
);
986 LOG_MEDIAPLAYER ("MediaPlayer::Pause (), state: %i [Done]\n", state_unlocked
);
990 MediaPlayer::GetTargetPts ()
999 LOG_MEDIAPLAYER_EX ("MediaPlayer::GetTargetPts (): target_pts: %" G_GUINT64_FORMAT
", HasAudio (): %i, audio->GetCurrentPts (): %" G_GUINT64_FORMAT
"\n", target_pts
, audio
!= NULL
, audio
!= NULL
? audio
->GetCurrentPts () : 0);
1001 if (audio
!= NULL
&& audio
->GetState () == AudioPlaying
)
1002 result
= audio
->GetCurrentPts ();
1004 result
= target_pts
;
1013 MediaPlayer::SeekCompletedHandler (Media
*media
, EventArgs
*args
)
1015 LOG_MEDIAPLAYER ("MediaPlayer::SeekCompletedHandler ()\n");
1018 RemoveBit (Seeking
);
1020 SetBit (LoadFramePending
);
1026 MediaPlayer::NotifySeek (guint64 pts
)
1028 LOG_MEDIAPLAYER ("MediaPlayer::Seek (%" G_GUINT64_FORMAT
" = %" G_GUINT64_FORMAT
" ms), media: %p, state: %i, current_pts: %llu, IsPlaying (): %i\n", pts
, MilliSeconds_FromPts (pts
), media
, state_unlocked
, current_pts
, IsPlaying ());
1031 guint64 duration
= GetDuration ();
1033 g_return_if_fail (GetCanSeek ());
1035 if (pts
> start_pts
+ duration
)
1036 pts
= start_pts
+ duration
;
1038 if (pts
< start_pts
)
1046 SetBit (LoadFramePending
);
1047 RemoveBit (SeekSynched
);
1048 RemoveBit (AudioEnded
);
1049 RemoveBit (VideoEnded
);
1055 LOG_MEDIAPLAYER ("MediaPlayer::Seek (%" G_GUINT64_FORMAT
" = %" G_GUINT64_FORMAT
" ms), media: %p, state: %i, current_pts: %llu [END]\n", pts
, MilliSeconds_FromPts (pts
), media
, state_unlocked
, current_pts
);
1059 MediaPlayer::GetCanSeek ()
1062 return GetBit (CanSeek
);
1066 MediaPlayer::SetCanSeek (bool value
)
1069 SetBitTo (CanSeek
, value
);
1073 MediaPlayer::Stop ()
1075 LOG_MEDIAPLAYER ("MediaPlayer::Stop (), state: %i\n", state_unlocked
);
1086 RemoveBit (AudioEnded
);
1087 RemoveBit (VideoEnded
);
1091 MediaPlayer::StopAudio ()
1095 LOG_MEDIAPLAYER ("MediaPlayer::StopAudio (), state: %i\n", state_unlocked
);
1098 audio
= GetAudio (); // This returns a reffed AudioSource
1106 MediaPlayer::GetBalance ()
1113 audio
= GetAudio ();
1115 result
= audio
->GetBalance ();
1118 fprintf (stderr
, "MediaPlayer::GetBalance (): There's no audio source to get the balance from\n");
1126 MediaPlayer::SetBalance (double balance
)
1130 LOG_MEDIAPLAYER ("MediaPlayer::SetBalance (%f)\n", balance
);
1135 else if (balance
> 1.0)
1138 audio
= GetAudio ();
1140 audio
->SetBalance (balance
);
1143 //fprintf (stderr, "MediaPlayer::SetBalance (%f): There's no audio source to set the balance\n", balance);
1148 MediaPlayer::GetVolume ()
1156 result
= audio
->GetVolume ();
1159 fprintf (stderr
, "MediaPlayer::GetVolume (): There's no audio source to get the volume from\n");
1167 MediaPlayer::SetVolume (double volume
)
1171 LOG_MEDIAPLAYER ("MediaPlayer::SetVolume (%f)\n", volume
);
1176 else if (volume
> 1.0)
1179 audio
= GetAudio ();
1181 audio
->SetVolume (volume
);
1184 //fprintf (stderr, "MediaPlayer::SetVolume (%f): There's no audio source to set the volume\n", volume);
1189 MediaPlayer::GetMuted ()
1196 audio
= GetAudio ();
1198 result
= audio
->GetMuted ();
1201 fprintf (stderr
, "MediaPlayer::GetMuted (): There's no audio.\n");
1209 MediaPlayer::SetMuted (bool muted
)
1213 LOG_MEDIAPLAYER ("MediaPlayer::SetMuted (%i)\n", muted
);
1216 audio
= GetAudio ();
1218 audio
->SetMuted (true);
1221 //fprintf (stderr, "MediaPlayer::SetMuted (%i): There's no audio to mute.\n", muted);
1226 MediaPlayer::SetBit (PlayerState s
)
1229 state_unlocked
= (PlayerState
) (s
| state_unlocked
);
1234 MediaPlayer::RemoveBit (PlayerState s
)
1237 state_unlocked
= (PlayerState
) (~s
& state_unlocked
);
1242 MediaPlayer::SetBitTo (PlayerState s
, bool value
)
1252 MediaPlayer::GetBit (PlayerState s
)
1256 result
= (state_unlocked
& s
) == s
;
1262 MediaPlayer::SetState (PlayerState s
)
1265 state_unlocked
= (PlayerState
) ((state_unlocked
& ~StateMask
) | s
);
1269 MediaPlayer::PlayerState
1270 MediaPlayer::GetState ()
1274 result
= state_unlocked
;
1280 MediaPlayer::IsBufferUnderflow ()
1282 return GetBit (BufferUnderflow
);
1286 MediaPlayer::IsLoadFramePending ()
1288 return GetBit (LoadFramePending
);
1292 MediaPlayer::IsSeeking ()
1294 return GetBit (Seeking
);
1298 MediaPlayer::HasRenderedFrame ()
1300 return GetBit (RenderedFrame
);
1304 MediaPlayer::IsPlaying ()
1306 return (GetState () & StateMask
) == Playing
;
1310 MediaPlayer::IsPaused ()
1312 return (GetState () & StateMask
) == Paused
;
1316 MediaPlayer::IsStopped ()
1318 return (GetState () & StateMask
) == Stopped
;
1322 MediaPlayer::SetBufferUnderflow ()
1324 SetBitTo (BufferUnderflow
, true);
1325 EmitBufferUnderflow ();
1329 MediaPlayer::EmitBufferUnderflow ()
1331 if (Surface::InMainThread ()) {
1332 Emit (BufferUnderflowEvent
);
1334 AddTickCallSafe (EmitBufferUnderflowAsync
);
1339 MediaPlayer::EmitBufferUnderflowAsync (EventObject
*obj
)
1341 ((MediaPlayer
*) obj
)->EmitBufferUnderflow ();