1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * pipeline.cpp: Pipeline for the media
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.
17 #include <sys/types.h>
30 #include "codec-version.h"
31 #include "pipeline-ffmpeg.h"
35 #include "mediaelement.h"
37 #include "asf/asf-structures.h"
38 #include "yuv-converter.h"
40 #include "mms-downloader.h"
41 #include "pipeline-ui.h"
42 #include "pipeline-asf.h"
44 #include "deployment.h"
50 bool Media::registering_ms_codecs
= false;
51 bool Media::registered_ms_codecs
= false;
53 DemuxerInfo
*Media::registered_demuxers
= NULL
;
54 DecoderInfo
*Media::registered_decoders
= NULL
;
55 ConverterInfo
*Media::registered_converters
= NULL
;
56 gint32
Media::media_thread_count
= 0;
58 Media::Media (PlaylistRoot
*root
)
59 : IMediaObject (Type::MEDIA
, this)
61 pthread_attr_t attribs
;
63 LOG_PIPELINE ("Media::Media (), id: %i\n", GET_OBJ_ID (this));
65 queued_requests
= new List ();
80 error_reported
= false;
81 buffering_enabled
= false;
82 in_open_internal
= false;
84 download_progress
= 0.0;
85 buffering_progress
= 0.0;
87 // Last thing we do is to start up the media thread.
88 // TODO: only start up if we actually get work.
89 pthread_attr_init (&attribs
);
90 pthread_attr_setdetachstate (&attribs
, PTHREAD_CREATE_JOINABLE
);
91 pthread_mutex_init (&queue_mutex
, NULL
);
92 pthread_cond_init (&queue_condition
, NULL
);
93 pthread_create (&queue_thread
, &attribs
, WorkerLoop
, this);
94 pthread_attr_destroy (&attribs
);
96 GetDeployment ()->AddHandler (Deployment::ShuttingDownEvent
, ShuttingDownCallback
, this);
101 LOG_PIPELINE ("Media::~Media (), id: %i\n", GET_OBJ_ID (this));
102 pthread_mutex_destroy (&queue_mutex
);
103 pthread_cond_destroy (&queue_condition
);
107 Media::ShuttingDownHandler (Deployment
*obj
, EventArgs
*args
)
119 LOG_PIPELINE ("Media::Dispose (), id: %i\n", GET_OBJ_ID (this));
123 if (!stopped
&& !InMediaThread ())
124 pthread_join (queue_thread
, NULL
);
139 this->demuxer
= NULL
;
148 if (Surface::InMainThread ()) {
149 RemoveShuttingDownHandler (this);
151 AddTickCallSafe (RemoveShuttingDownHandler
);
154 IMediaObject::Dispose ();
158 Media::RemoveShuttingDownHandler (EventObject
*obj
)
161 // event handling must be done on the main thread
162 obj
->GetDeployment ()->RemoveHandler (Deployment::ShuttingDownEvent
, ShuttingDownCallback
, obj
);
166 Media::IsMSCodecsInstalled ()
168 return registered_ms_codecs
;
172 Media::RegisterMSCodecs (void)
176 char *libmscodecs_path
= NULL
;
177 const char *functions
[] = {"register_codec_pack", NULL
};
178 const gchar
*home
= g_get_home_dir ();
179 registering_ms_codecs
= true;
181 if (!(moonlight_flags
& RUNTIME_INIT_ENABLE_MS_CODECS
)) {
182 LOG_CODECS ("Moonlight: mscodecs haven't been enabled.\n");
187 libmscodecs_path
= g_build_filename (g_get_home_dir (), ".mozilla", "plugins", "moonlight", CODEC_LIBRARY_NAME
, NULL
);
189 if (!(g_file_test (libmscodecs_path
, G_FILE_TEST_EXISTS
) && g_file_test (libmscodecs_path
, G_FILE_TEST_IS_REGULAR
))) {
190 if (libmscodecs_path
)
191 g_free (libmscodecs_path
);
192 libmscodecs_path
= g_strdup (CODEC_LIBRARY_NAME
);
195 dl
= dlopen (libmscodecs_path
, RTLD_LAZY
);
197 LOG_CODECS ("Moonlight: Loaded mscodecs from: %s.\n", libmscodecs_path
);
199 for (int i
= 0; functions
[i
] != NULL
; i
++) {
200 reg
= (register_codec
) dlsym (dl
, functions
[i
]);
202 (*reg
) (MOONLIGHT_CODEC_ABI_VERSION
);
204 LOG_CODECS ("Moonlight: Cannot find %s in %s.\n", functions
[i
], libmscodecs_path
);
207 registered_ms_codecs
= true;
209 LOG_CODECS ("Moonlight: Cannot load %s: %s\n", libmscodecs_path
, dlerror ());
211 g_free (libmscodecs_path
);
213 registering_ms_codecs
= false;
217 Media::SetBufferingEnabled (bool value
)
219 buffering_enabled
= value
;
224 Media::SetBufferingTime (guint64 buffering_time
)
226 pthread_mutex_lock (&queue_mutex
);
227 this->buffering_time
= buffering_time
;
228 pthread_mutex_unlock (&queue_mutex
);
231 demuxer
->FillBuffers ();
235 Media::GetBufferingTime ()
238 pthread_mutex_lock (&queue_mutex
);
239 result
= buffering_time
;
240 pthread_mutex_unlock (&queue_mutex
);
245 Media::GetPlaylistRoot ()
254 markers
= new List ();
260 Media::RegisterDemuxer (DemuxerInfo
*info
)
262 //printf ("Media::RegisterDemuxer (%p - %s)\n", info, info->GetName ());
264 if (registered_demuxers
== NULL
) {
265 registered_demuxers
= info
;
267 MediaInfo
* current
= registered_demuxers
;
268 while (current
->next
!= NULL
)
269 current
= current
->next
;
270 current
->next
= info
;
275 Media::RegisterConverter (ConverterInfo
*info
)
277 //printf ("Media::RegisterConverter (%p)\n", info);
279 if (registered_converters
== NULL
) {
280 registered_converters
= info
;
282 MediaInfo
*current
= registered_converters
;
283 while (current
->next
!= NULL
)
284 current
= current
->next
;
285 current
->next
= info
;
290 Media::RegisterDecoder (DecoderInfo
*info
)
294 //printf ("Media::RegisterDecoder (%p)\n", info);
296 if (registered_decoders
== NULL
) {
297 registered_decoders
= info
;
299 if (registering_ms_codecs
) {
300 // MS codecs might get registered after all other codecs (right after installing them),
301 // which means after the null codecs so if they don't get special treatment, they won't
302 // get used until the next browser restart (when they're registered normally).
303 // So instead of appending them, we prepend them.
304 info
->next
= registered_decoders
;
305 registered_decoders
= info
;
307 current
= registered_decoders
;
308 while (current
->next
!= NULL
)
309 current
= current
->next
;
310 current
->next
= info
;
313 LOG_CODECS ("Moonlight: Codec has been registered: %s\n", info
->GetName ());
319 LOG_PIPELINE ("Media::Initialize ()\n");
322 Media::RegisterDemuxer (new ASFDemuxerInfo ());
323 Media::RegisterDemuxer (new Mp3DemuxerInfo ());
324 Media::RegisterDemuxer (new ASXDemuxerInfo ());
327 if (!(moonlight_flags
& RUNTIME_INIT_FFMPEG_YUV_CONVERTER
))
328 Media::RegisterConverter (new YUVConverterInfo ());
331 Media::RegisterDecoder (new ASFMarkerDecoderInfo ());
332 if (moonlight_flags
& RUNTIME_INIT_ENABLE_MS_CODECS
) {
335 #ifdef INCLUDE_FFMPEG
336 if (!(moonlight_flags
& RUNTIME_INIT_DISABLE_FFMPEG_CODECS
)) {
341 Media::RegisterDecoder (new PassThroughDecoderInfo ());
342 Media::RegisterDecoder (new NullDecoderInfo ());
348 LOG_PIPELINE ("Media::Shutdown ()\n");
353 current
= registered_decoders
;
354 while (current
!= NULL
) {
355 next
= current
->next
;
359 registered_decoders
= NULL
;
361 current
= registered_demuxers
;
362 while (current
!= NULL
) {
363 next
= current
->next
;
367 registered_demuxers
= NULL
;
369 current
= registered_converters
;
370 while (current
!= NULL
) {
371 next
= current
->next
;
375 registered_converters
= NULL
;
377 // Make sure all threads are stopped
378 AudioPlayer::Shutdown ();
380 LOG_PIPELINE ("Media::Shutdown () [Done]\n");
384 Media::Warning (MediaResult result
, const char *format
, ...)
388 if (MEDIA_SUCCEEDED (result
))
391 fprintf (stderr
, "Moonlight: MediaResult = %d; ", result
);
393 va_start (args
, format
);
394 vfprintf (stderr
, format
, args
);
397 fputc ('\n', stderr
);
401 Media::InMediaThread ()
403 return pthread_equal (queue_thread
, pthread_self ());
407 Media::ReportBufferingProgress (double progress
)
409 LOG_BUFFERING ("Media::ReportBufferingProgress (%.3f), buffering_progress: %.3f\n", progress
, buffering_progress
);
411 progress
= MAX (MIN (progress
, 1.0), 0.0);
413 if (progress
== buffering_progress
)
416 if (progress
< buffering_progress
|| progress
> (buffering_progress
+ 0.005) || progress
== 1.0 || progress
== 0.0) {
417 buffering_progress
= progress
;
418 EmitSafe (BufferingProgressChangedEvent
, new ProgressEventArgs (progress
));
423 Media::ReportDownloadProgress (double progress
)
425 LOG_PIPELINE ("Media::ReportDownloadProgress (%.3f), download_progress: %.3f\n", progress
, download_progress
);
427 progress
= MAX (MIN (progress
, 1.0), 0.0);
429 // download progress can only go up
430 g_return_if_fail (progress
>= download_progress
);
432 if (progress
== download_progress
)
435 if (progress
> (download_progress
+ 0.005) || progress
== 1.0 || progress
== 0.0) {
436 download_progress
= progress
;
437 EmitSafe (DownloadProgressChangedEvent
, new ProgressEventArgs (progress
));
442 Media::SeekAsync (guint64 pts
)
444 LOG_PIPELINE ("Media::SeekAsync (%" G_GUINT64_FORMAT
"), id: %i\n", pts
, GET_OBJ_ID (this));
446 if (demuxer
== NULL
) {
447 ReportErrorOccurred ("Media::SeekAsync was called, but there is no demuxer to seek on.\n");
451 demuxer
->SeekAsync (pts
);
455 Media::ReportSeekCompleted (guint64 pts
)
457 LOG_PIPELINE ("Media::ReportSeekCompleted (%llu), id: %i\n", pts
, GET_OBJ_ID (this));
459 buffering_progress
= 0;
460 EmitSafe (SeekCompletedEvent
);
464 Media::ReportOpenCompleted ()
466 LOG_PIPELINE ("Media::ReportOpenCompleted (), id: %i\n", GET_OBJ_ID (this));
468 EmitSafe (OpenCompletedEvent
);
472 Media::ReportOpenDemuxerCompleted ()
474 LOG_PIPELINE ("Media::ReportOpenDemuxerCompleted (), id: %i\n", GET_OBJ_ID (this));
480 Media::ReportOpenDecoderCompleted (IMediaDecoder
*decoder
)
482 LOG_PIPELINE ("Media::ReportOpenDecoderCompleted (%p), id: %i\n", decoder
, GET_OBJ_ID (this));
484 g_return_if_fail (decoder
!= NULL
);
490 Media::ReportErrorOccurred (ErrorEventArgs
*args
)
492 LOG_PIPELINE ("Media::ReportErrorOccurred (%p %s)\n", args
, args
== NULL
? NULL
: args
->error_message
);
495 fprintf (stderr
, "Moonlight: %s %i %s %s\n", enums_int_to_str ("ErrorType", args
->error_type
), args
->error_code
, args
->error_message
, args
->extended_message
);
497 fprintf (stderr
, "Moonlight: Unspecified media error.\n");
500 if (!error_reported
) {
501 error_reported
= true;
502 EmitSafe (MediaErrorEvent
, args
);
507 Media::ReportErrorOccurred (const char *message
)
509 LOG_PIPELINE ("Media::ReportErrorOccurred (%s)\n", message
);
511 ReportErrorOccurred (new ErrorEventArgs (MediaError
, 3001, message
));
515 Media::ReportErrorOccurred (MediaResult result
)
517 char *msg
= g_strdup_printf ("Media error: %i.", result
);
518 ReportErrorOccurred (msg
);
525 LOG_PIPELINE ("Media::PlayAsync ()\n");
531 LOG_PIPELINE ("Media::PauseAsync ()\n");
537 LOG_PIPELINE ("Media::StopAsync ()\n");
541 Media::Initialize (Downloader
*downloader
, const char *PartName
)
543 IMediaSource
*source
;
545 LOG_PIPELINE ("Media::Initialize (%p, '%s'), id: %i\n", downloader
, PartName
, GET_OBJ_ID (this));
547 g_return_if_fail (downloader
!= NULL
);
548 g_return_if_fail (file
== NULL
);
549 g_return_if_fail (uri
!= NULL
|| PartName
!= NULL
);
550 g_return_if_fail (initialized
== false);
551 g_return_if_fail (error_reported
== false);
552 g_return_if_fail (this->source
== NULL
);
554 if (downloader
->Completed ()) {
555 file
= downloader
->GetDownloadedFilename (PartName
);
558 ReportErrorOccurred ("Couldn't get downloaded filename.");
563 if (file
== NULL
&& PartName
!= NULL
&& PartName
[0] != 0) {
564 ReportErrorOccurred ("We don't support using media in zip files which haven't been downloaded yet (i.e. calling MediaElement.SetSource (dl, 'foo') with a dl which hasn't downloaded the file yet)");
569 InternalDownloader
*idl
= downloader
->GetInternalDownloader ();
570 MmsDownloader
*mms_dl
= (idl
&& idl
->GetObjectType () == Type::MMSDOWNLOADER
) ? (MmsDownloader
*) idl
: NULL
;
572 if (mms_dl
== NULL
) {
573 ReportErrorOccurred ("We don't support using downloaders which haven't started yet.");
577 source
= new MmsSource (this, downloader
);
579 source
= new FileSource (this, file
);
587 Media::Initialize (IMediaSource
*source
)
591 LOG_PIPELINE ("Media::Initialize (%p), id: %i\n", source
, GET_OBJ_ID (this));
593 g_return_if_fail (source
!= NULL
);
594 g_return_if_fail (this->source
== NULL
);
595 g_return_if_fail (initialized
== false);
597 result
= source
->Initialize ();
598 if (!MEDIA_SUCCEEDED (result
)) {
599 ReportErrorOccurred (result
);
604 this->source
= source
;
605 this->source
->ref ();
609 Media::Initialize (const char *uri
)
612 IMediaSource
*source
= NULL
;
614 LOG_PIPELINE ("Media::Initialize ('%s'), id: %i\n", uri
, GET_OBJ_ID (this));
616 g_return_if_fail (uri
!= NULL
);
617 g_return_if_fail (file
== NULL
);
618 g_return_if_fail (uri
!= NULL
);
619 g_return_if_fail (initialized
== false);
620 g_return_if_fail (error_reported
== false);
621 g_return_if_fail (source
== NULL
);
622 g_return_if_fail (this->source
== NULL
);
624 this->uri
= g_strdup (uri
);
627 if (g_str_has_prefix (uri
, "mms://") || g_str_has_prefix (uri
, "rtsp://") || g_str_has_prefix (uri
, "rtsps://")) {
628 dl
= Surface::CreateDownloader (this);
630 ReportErrorOccurred ("Couldn't create downloader.");
634 dl
->Open ("GET", uri
, StreamingPolicy
);
636 if (dl
->GetFailedMessage () == NULL
) {
637 Initialize (dl
, NULL
);
639 ReportErrorOccurred (new ErrorEventArgs (MediaError
, 4001, "AG_E_NETWORK_ERROR"));
647 source
= new ProgressiveSource (this, uri
);
653 Media::Initialize (IMediaDemuxer
*demuxer
)
655 LOG_PIPELINE ("Media::Initialize (%p), id: %i\n", demuxer
, GET_OBJ_ID (this));
657 g_return_if_fail (demuxer
!= NULL
);
658 g_return_if_fail (this->demuxer
== NULL
);
659 g_return_if_fail (initialized
== false);
661 this->demuxer
= demuxer
;
662 this->demuxer
->ref ();
669 Media::RetryHttp (ErrorEventArgs
*args
)
671 char *http_uri
= NULL
;
673 LOG_PIPELINE ("Media::RetryHttp (), current uri: '%s'\n", uri
);
675 g_return_if_fail (uri
!= NULL
);
676 g_return_if_fail (source
!= NULL
);
679 ReportErrorOccurred (args
);
683 // CHECK: If the current protocolo is rtsps, should we retry http or https?
685 if (g_str_has_prefix (uri
, "mms://")) {
686 http_uri
= g_strdup_printf ("http://%s", uri
+ 6);
687 } else if (g_str_has_prefix (uri
, "rtsp://")) {
688 http_uri
= g_strdup_printf ("http://%s", uri
+ 7);
689 } else if (g_str_has_prefix (uri
, "rtsps://")) {
690 http_uri
= g_strdup_printf ("http://%s", uri
+ 8);
692 ReportErrorOccurred (args
);
698 LOG_PIPELINE ("Media::RetryHttp (), new uri: '%s'\n", http_uri
);
707 Initialize (http_uri
);
718 LOG_PIPELINE ("Media::OpenAsync (), id: %i\n", GET_OBJ_ID (this));
720 g_return_if_fail (initialized
== true);
722 EmitSafe (OpeningEvent
);
728 Media::OpenInternal ()
730 LOG_PIPELINE ("Media::OpenInternal (), id: %i\n", GET_OBJ_ID (this));
732 g_return_if_fail (initialized
== true);
735 // This may happen due to the recursion detection below
736 // Example: we try open a demuxer, the demuxer opens successfully
737 // right away and calls ReportDemuxerOpenComplete which will call
738 // us. Due to the recursion detection we'll enqueue a call to
739 // OpenInternal, while the first OpenInternal may succeed and
740 // set opened to true.
741 LOG_PIPELINE ("Media::OpenInteral (): already opened.\n");
745 // detect recursive calls.
747 if (in_open_internal
) {
748 LOG_PIPELINE ("Media::OpenInteral (): recursive.\n");
749 MediaClosure
*closure
= new MediaClosure (this, OpenInternal
, this);
750 EnqueueWork (closure
);
755 in_open_internal
= true;
760 if (!SelectDemuxerAsync ()) {
761 LOG_PIPELINE ("Media::OpenInteral (): no demuxer yet.\n");
768 if (!SelectDecodersAsync ()) {
769 LOG_PIPELINE ("Media::OpenInteral (): no decoders yet.\n");
773 demuxer
->FillBuffers ();
778 LOG_PIPELINE ("Media::OpenInteral (): opened successfully.\n");
780 EmitSafe (OpenCompletedEvent
);
783 in_open_internal
= false;
787 Media::OpenInternal (MediaClosure
*closure
)
789 Media
*media
= (Media
*) closure
->GetContext ();
791 g_return_val_if_fail (media
!= NULL
, MEDIA_FAIL
);
793 media
->OpenInternal ();
795 return MEDIA_SUCCESS
;
799 Media::SelectDemuxerAsync ()
801 DemuxerInfo
*demuxerInfo
;
806 LOG_PIPELINE ("Media::SelectDemuxer () id: %i, demuxer: %p, IsOpened: %i, IsOpening: %i\n", GET_OBJ_ID (this), demuxer
, demuxer
? demuxer
->IsOpened () : -1, demuxer
? demuxer
->IsOpening () : -1);
808 g_return_val_if_fail (error_reported
== false, false);
809 g_return_val_if_fail (initialized
== true, false);
811 // Check if demuxer already is open
812 if (demuxer
!= NULL
) {
813 if (demuxer
->IsOpened ())
815 if (!demuxer
->IsOpening ())
816 demuxer
->OpenDemuxerAsync ();
817 return demuxer
->IsOpened ();
820 g_return_val_if_fail (source
!= NULL
, false);
822 // Check if the source knows how to create the demuxer
823 demuxer
= source
->CreateDemuxer (this);
825 if (demuxer
== NULL
) { // No demuxer created, we need to find it ourselves.
826 // Check if we have at least 1024 bytes or eof
827 if (!source
->IsPositionAvailable (16, &eof
)) {
829 // We need to try again later.
830 LOG_PIPELINE ("Media::SelectDemuxer (): We don't have enough data yet.\n");
832 MediaClosure
*closure
= new MediaClosure (this, OpenInternal
, this);
833 EnqueueWork (closure
, false);
841 demuxerInfo
= registered_demuxers
;
842 while (demuxer
== NULL
&& demuxerInfo
!= NULL
) {
843 LOG_PIPELINE ("Media::SelectDemuxer ): Checking if '%s' can handle the media.\n", demuxerInfo
->GetName ());
844 support
= demuxerInfo
->Supports (source
);
846 if (support
== MEDIA_SUCCESS
)
851 if (result
== MEDIA_NOT_ENOUGH_DATA
) {
852 LOG_PIPELINE ("Media::SelectDemuxer (): '%s' can't determine whether it can handle the media or not due to not enough data being available yet.\n", demuxerInfo
->GetName ());
854 MediaClosure
*closure
= new MediaClosure (this, OpenInternal
, this);
855 EnqueueWork (closure
, false);
861 LOG_PIPELINE ("Media::SelectDemuxer (): '%s' can't handle this media.\n", demuxerInfo
->GetName ());
862 demuxerInfo
= (DemuxerInfo
*) demuxerInfo
->next
;
865 if (demuxerInfo
== NULL
) {
866 // No demuxer found, report an error
867 const char *source_name
= file
? file
: uri
;
870 switch (source
->GetType ()) {
871 case MediaSourceTypeProgressive
:
872 case MediaSourceTypeFile
:
873 source_name
= ((FileSource
*) source
)->GetFileName ();
875 case MediaSourceTypeMms
:
876 case MediaSourceTypeMmsEntry
:
877 source_name
= "live source";
880 source_name
= "unknown source";
884 char *msg
= g_strdup_printf ("No demuxers registered to handle the media source '%s'.", source_name
);
885 ReportErrorOccurred (new ErrorEventArgs (MediaError
, 3001, "AG_E_INVALID_FILE_FORMAT", MEDIA_UNKNOWN_CODEC
, msg
));
891 demuxer
= demuxerInfo
->Create (this, source
);
893 LOG_PIPELINE ("Media::SelectDemuxer (): The source created the demuxer (%s).\n", demuxer
->GetTypeName ());
896 if (demuxer
->IsOpened ())
899 if (demuxer
->IsOpening ())
902 LOG_PIPELINE ("Media::SelectDemuxer (), id: %i opening demuxer %i (%s)\n", GET_OBJ_ID (this), GET_OBJ_ID (demuxer
), demuxer
->GetTypeName ());
904 demuxer
->OpenDemuxerAsync ();
906 LOG_PIPELINE ("Media::SelectDemuxer (), id: %i opening demuxer %i (%s) [Done]\n", GET_OBJ_ID (this), GET_OBJ_ID (demuxer
), demuxer
->GetTypeName ());
908 return demuxer
!= NULL
&& demuxer
->IsOpened ();
912 Media::SelectDecodersAsync ()
914 LOG_PIPELINE ("Media::SelectDecodersAsync () id: %i.\n", GET_OBJ_ID (this));
916 g_return_val_if_fail (error_reported
== false, false);
917 g_return_val_if_fail (initialized
== true, false);
919 if (demuxer
== NULL
) {
920 ReportErrorOccurred ("No demuxer to select decoders from.");
924 // If the demuxer has no streams (ASXDemuxer for instance)
925 // then just return success.
926 if (demuxer
->GetStreamCount () == 0)
929 LOG_PIPELINE ("Media::SelectDecodersAsync (): Selecting decoders.\n");
931 // Select codecs for each stream
932 for (int i
= 0; i
< demuxer
->GetStreamCount (); i
++) {
933 IMediaStream
*stream
= demuxer
->GetStream (i
);
936 if (stream
== NULL
) {
937 ReportErrorOccurred ("MEDIA_INVALID_STREAM");
941 if (stream
->GetDecoder () != NULL
)
944 const char *codec
= stream
->GetCodec ();
945 IMediaDecoder
*decoder
= NULL
;
947 LOG_CODECS ("Moonlight: Searching registered decoders for a decoder which supports '%s'\n", codec
);
949 DecoderInfo
*current_decoder
= registered_decoders
;
950 while (current_decoder
!= NULL
&& !current_decoder
->Supports (codec
)) {
951 LOG_CODECS ("Moonlight: Checking if registered decoder '%s' supports codec '%s': no.\n", current_decoder
->GetName (), codec
);
952 current_decoder
= (DecoderInfo
*) current_decoder
->next
;
955 if (current_decoder
== NULL
) {
956 Media::Warning (MEDIA_UNKNOWN_CODEC
, "Unknown codec: '%s'.", codec
);
960 LOG_CODECS ("Moonlight: Checking if registered decoder '%s' supports codec '%s': yes.\n", current_decoder
->GetName (), codec
);
961 decoder
= current_decoder
->Create (this, stream
);
963 stream
->SetDecoder (decoder
);
971 LOG_PIPELINE ("Media::SelectDecodersAsync (): Opening decoders.\n");
973 for (int i
= 0; i
< demuxer
->GetStreamCount (); i
++) {
974 IMediaStream
*stream
= demuxer
->GetStream (i
);
975 IMediaDecoder
*decoder
;
980 decoder
= stream
->GetDecoder ();
982 if (decoder
== NULL
) {
983 ReportErrorOccurred (new ErrorEventArgs (MediaError
, 3001, "AG_E_INVALID_FILE_FORMAT"));
987 if (decoder
->IsOpening () || decoder
->IsOpened ())
990 decoder
->OpenDecoderAsync ();
996 // Wait until all the codecs have opened
997 LOG_PIPELINE ("Media::SelectDecodersAsync (): Waiting for decoders to open.\n");
999 for (int i
= 0; i
< demuxer
->GetStreamCount (); i
++) {
1000 IMediaStream
*stream
= demuxer
->GetStream (i
);
1001 IMediaDecoder
*decoder
;
1006 decoder
= stream
->GetDecoder ();
1008 if (decoder
== NULL
) {
1009 ReportErrorOccurred (MEDIA_FAIL
);
1013 if (decoder
->IsOpening ()) {
1014 MediaClosure
*closure
= new MediaClosure (this, OpenInternal
, this);
1015 EnqueueWork (closure
, false);
1020 if (!decoder
->IsOpened ()) {
1021 // After calling OpenDecoderAsync on a decoder, the decoder should either be opened, opening, or an error should have occurred.
1022 ReportErrorOccurred (MEDIA_FAIL
);
1028 // All the codecs have been opened now.
1029 // Find converters for each of them (whenever required).
1031 LOG_PIPELINE ("Media::SelectDecodersAsync (): Selecting converters.\n");
1033 for (int i
= 0; i
< demuxer
->GetStreamCount (); i
++) {
1034 IMediaStream
*stream
= demuxer
->GetStream (i
);
1035 IMediaDecoder
*decoder
;
1040 decoder
= stream
->GetDecoder ();
1042 if (decoder
== NULL
) {
1043 ReportErrorOccurred (MEDIA_FAIL
);
1047 if (stream
->GetType () != MediaTypeVideo
)
1048 continue; // Only video streams need converters
1050 if (decoder
->GetPixelFormat () == MoonPixelFormatRGB32
|| decoder
->GetPixelFormat () == MoonPixelFormatRGBA32
)
1051 continue; // We need RGB32, so any stream already producing RGB32 doesn't need a converter.
1053 // Select converter for this stream
1054 VideoStream
*vs
= (VideoStream
*) stream
;
1056 ConverterInfo
* current_conv
= registered_converters
;
1057 while (current_conv
!= NULL
&& !current_conv
->Supports (decoder
->GetPixelFormat (), MoonPixelFormatRGB32
)) {
1058 LOG_PIPELINE ("Checking whether '%s' supports input '%d' and output '%d': no.\n",
1059 current_conv
->GetName (), decoder
->GetPixelFormat (), MoonPixelFormatRGB32
);
1060 current_conv
= (ConverterInfo
*) current_conv
->next
;
1064 if (current_conv
== NULL
) {
1065 ReportErrorOccurred (MEDIA_UNKNOWN_CONVERTER
);
1066 //Media::Warning (MEDIA_UNKNOWN_CONVERTER, "Can't convert from %d to %d: No converter found.",
1067 // decoder->GetPixelFormat (), MoonPixelFormatRGB32);
1071 LOG_PIPELINE ("Checking whether '%s' supports input '%d' and output '%d': yes.\n",
1072 current_conv
->GetName (), decoder
->GetPixelFormat (), MoonPixelFormatRGB32
);
1074 vs
->converter
= current_conv
->Create (this, vs
);
1075 vs
->converter
->input_format
= decoder
->GetPixelFormat ();
1076 vs
->converter
->output_format
= MoonPixelFormatRGB32
;
1077 if (!MEDIA_SUCCEEDED (vs
->converter
->Open ())) {
1078 vs
->converter
->unref ();
1079 vs
->converter
= NULL
;
1080 ReportErrorOccurred (MEDIA_FAIL
);
1085 // Loop through all the streams, return true if at least one has a codec.
1087 for (int i
= 0; i
< demuxer
->GetStreamCount (); i
++) {
1088 IMediaStream
*stream
= demuxer
->GetStream (i
);
1093 if (stream
->GetDecoder () != NULL
)
1097 // No codecs found for no stream, report an error.
1098 ReportErrorOccurred ("Didn't find any codecs for any stream.");
1103 Media::WorkerLoop (void *data
)
1105 Media
*media
= (Media
*) data
;
1107 g_atomic_int_exchange_and_add (&media_thread_count
, 1);
1109 LOG_PIPELINE ("Media::WorkerLoop (%p id: %i). New media thread. Current media thread count: %i\n", media
, GET_OBJ_ID (media
), media_thread_count
);
1111 media
->WorkerLoop ();
1113 g_atomic_int_dec_and_test (&media_thread_count
);
1115 LOG_PIPELINE ("Media::WorkerLoop (%p id: %i). Stopped media thread. Current media thread count: %i\n", media
, GET_OBJ_ID (media
), media_thread_count
);
1121 Media::WorkerLoop ()
1123 MediaResult result
= MEDIA_SUCCESS
;
1125 LOG_PIPELINE ("Media::WorkerLoop ().\n");
1127 // This works since we have 1 thread per Media.
1128 // When each thread may process work for > 1 Media,
1129 // we need to set the deployment before processing
1130 // each each work item.
1131 Deployment::RegisterThread (GetDeployment ());
1132 Deployment::SetCurrent (GetDeployment ());
1134 while (queued_requests
!= NULL
&& !stopping
) {
1135 MediaWork
*node
= NULL
;
1137 LOG_FRAMEREADERLOOP ("Media::WorkerLoop (%p): entering mutex.\n", this);
1139 // Wait until we have something in the queue
1140 pthread_mutex_lock (&queue_mutex
);
1142 if (queued_requests
!= NULL
&& !stopping
&& queued_requests
->IsEmpty ())
1143 pthread_cond_wait (&queue_condition
, &queue_mutex
);
1145 if (queued_requests
!= NULL
) {
1146 node
= (MediaWork
*) queued_requests
->First ();
1148 queued_requests
->Unlink (node
);
1151 pthread_mutex_unlock (&queue_mutex
);
1153 if (queued_requests
== NULL
|| stopping
) {
1154 LOG_FRAMEREADERLOOP ("Media::WorkerLoop (%p): exiting.\n", this);
1159 continue; // Found nothing, continue waiting.
1161 LOG_FRAMEREADERLOOP ("Media::WorkerLoop (%p): got a node, there are %d nodes left.\n", this, queued_requests
->Length ());
1162 LOG_FRAMEREADERLOOP ("Media::WorkerLoop (%p): processing node %p.\n", this, node
);
1164 node
->closure
->Call ();
1166 LOG_FRAMEREADERLOOP ("Media::WorkerLoop (%p): processed node %p, result: %i.\n", this, node
, result
);
1173 LOG_PIPELINE ("Media::WorkerLoop (): exiting.\n");
1177 Media::EnqueueWork (MediaClosure
*closure
, bool wakeup
)
1182 LOG_PIPELINE_EX ("Media::EnqueueWork (%p).\n", closure
);
1184 g_return_val_if_fail (closure
!= NULL
, false);
1186 work
= new MediaWork (closure
);
1188 pthread_mutex_lock (&queue_mutex
);
1190 if (queued_requests
!= NULL
) {
1191 queued_requests
->Append (work
);
1199 pthread_cond_signal (&queue_condition
);
1201 pthread_mutex_unlock (&queue_mutex
);
1207 Media::DisposeObjectInternal (MediaClosure
*closure
)
1209 closure
->GetContext ()->Dispose ();
1210 return MEDIA_SUCCESS
;
1214 Media::DisposeObject (EventObject
*obj
)
1216 MediaDisposeObjectClosure
*closure
= new MediaDisposeObjectClosure (this, DisposeObjectInternal
, obj
);
1217 if (!EnqueueWork (closure
, true)) {
1219 printf ("Media::DisposeObject (%p): Could not add callback to the media thread, calling Dispose directly.\n", obj
);
1229 pthread_mutex_lock (&queue_mutex
);
1230 pthread_cond_signal (&queue_condition
);
1231 pthread_mutex_unlock (&queue_mutex
);
1235 Media::ClearQueue ()
1241 Media::ClearQueue (bool delete_queue
)
1243 LOG_PIPELINE ("Media::ClearQueue ().\n");
1244 if (queued_requests
!= NULL
) {
1246 List::Node
*current
= NULL
;
1248 pthread_mutex_lock (&queue_mutex
);
1249 if (queued_requests
!= NULL
) {
1250 current
= queued_requests
->First ();
1251 queued_requests
->Clear (false);
1253 delete queued_requests
;
1254 queued_requests
= NULL
;
1255 pthread_cond_signal (&queue_condition
);
1258 pthread_mutex_unlock (&queue_mutex
);
1260 // We have to delete the list nodes with the
1261 // queue mutex unlocked, due to refcounting
1262 // (our node's (MediaWork) dtor will cause unrefs,
1263 // which may cause other dtors to be called,
1264 // eventually ending up calling Dispose on this
1265 // Media instance, which will try to lock again
1266 // and therefore deadlock)
1267 while (current
!= NULL
) {
1268 next
= current
->next
;
1276 Media::StopThread ()
1278 LOG_PIPELINE ("Media::StopThread ().\n");
1286 pthread_join (queue_thread
, NULL
);
1288 LOG_PIPELINE ("Media::StopThread () [Done]\n");
1295 ASXDemuxer::ASXDemuxer (Media
*media
, IMediaSource
*source
)
1296 : IMediaDemuxer (Type::ASXDEMUXER
, media
, source
)
1301 ASXDemuxer::~ASXDemuxer ()
1306 ASXDemuxer::Dispose ()
1312 IMediaDemuxer::Dispose ();
1316 ASXDemuxer::OpenDemuxerAsyncInternal ()
1320 ErrorEventArgs
*args
= NULL
;
1321 Media
*media
= GetMediaReffed ();
1323 g_return_if_fail (media
!= NULL
);
1325 root
= media
->GetPlaylistRoot ();
1327 g_return_if_fail (root
!= NULL
);
1329 PlaylistParser
*parser
= new PlaylistParser (root
, source
);
1331 if (MEDIA_SUCCEEDED (parser
->Parse ())) {
1332 result
= MEDIA_SUCCESS
;
1333 playlist
= parser
->GetPlaylist ();
1336 result
= MEDIA_FAIL
;
1337 args
= parser
->GetErrorEventArgs ();
1344 if (MEDIA_SUCCEEDED (result
)) {
1345 ReportOpenDemuxerCompleted ();
1346 } else if (args
!= NULL
) {
1347 args
->ref (); // calling ReportErrorOccurred with an event args will end up unreffing it
1348 ReportErrorOccurred (args
);
1350 ReportErrorOccurred (result
);
1363 ASXDemuxerInfo::Supports (IMediaSource
*source
)
1365 if (PlaylistParser::IsASX2 (source
) || PlaylistParser::IsASX3 (source
)) {
1366 return MEDIA_SUCCESS
;
1373 ASXDemuxerInfo::Create (Media
*media
, IMediaSource
*source
)
1375 return new ASXDemuxer (media
, source
);
1379 * ManagedStreamSource
1382 ManagedStreamSource::ManagedStreamSource (Media
*media
, ManagedStreamCallbacks
*stream
) : IMediaSource (Type::MANAGEDSTREAMSOURCE
, media
)
1384 memcpy (&this->stream
, stream
, sizeof (this->stream
));
1387 ManagedStreamSource::~ManagedStreamSource ()
1389 stream
.handle
= NULL
;
1393 ManagedStreamSource::ReadInternal (void *buf
, guint32 n
)
1395 return stream
.Read (stream
.handle
, buf
, 0, n
);
1399 ManagedStreamSource::PeekInternal (void *buf
, guint32 n
)
1403 read
= stream
.Read (stream
.handle
, buf
, 0, n
);
1404 stream
.Seek (stream
.handle
, -read
, 1 /* SeekOrigin.Current */);
1409 ManagedStreamSource::SeekInternal (gint64 offset
, int mode
)
1411 stream
.Seek (stream
.handle
, offset
, mode
/* FIXME: check if mode values matches SeekOrigin values */);
1416 ManagedStreamSource::GetPositionInternal ()
1418 return stream
.Position (stream
.handle
);
1422 ManagedStreamSource::GetSizeInternal ()
1424 return stream
.Length (stream
.handle
);
1431 FileSource::FileSource (Media
*media
, const char *filename
) : IMediaSource (Type::FILESOURCE
, media
)
1433 this->filename
= g_strdup (filename
);
1439 FileSource::FileSource (Media
*media
, bool temp_file
) : IMediaSource (Type::FILESOURCE
, media
)
1444 this->temp_file
= temp_file
;
1447 FileSource::~FileSource ()
1452 FileSource::Dispose ()
1460 IMediaSource::Dispose ();
1464 FileSource::Initialize ()
1468 LOG_PIPELINE ("FileSource::Initialize ()\n");
1471 return MEDIA_SUCCESS
;
1474 if (filename
!= NULL
)
1475 return MEDIA_FILE_ERROR
;
1477 filename
= g_build_filename (g_get_tmp_dir (), "MoonlightProgressiveStream.XXXXXX", NULL
);
1479 if ((tmp_fd
= g_mkstemp (filename
)) == -1) {
1486 fd
= fdopen (tmp_fd
, "r");
1488 setvbuf (fd
, buffer
, _IOFBF
, sizeof (buffer
));
1490 if (filename
== NULL
)
1491 return MEDIA_FILE_ERROR
;
1493 fd
= fopen (filename
, "r");
1497 return MEDIA_FILE_ERROR
;
1501 return MEDIA_SUCCESS
;
1505 FileSource::Open (const char *filename
)
1507 g_return_val_if_fail (filename
!= NULL
, MEDIA_FAIL
);
1509 g_free (this->filename
);
1510 this->filename
= g_strdup (filename
);
1517 fd
= fopen (filename
, "r");
1524 return MEDIA_SUCCESS
;
1528 FileSource::UpdateSize ()
1532 g_return_if_fail (fd
!= NULL
);
1534 if (fstat (fileno (fd
), &st
) != -1) {
1542 FileSource::GetSizeInternal ()
1548 FileSource::GetPositionInternal ()
1555 result
= ftell (fd
);
1557 LOG_PIPELINE_EX ("FileSource::GetPositionInternal (): result: %lld\n", result
);
1563 FileSource::SeekInternal (gint64 offset
, int mode
)
1570 LOG_PIPELINE ("FileSource::SeekInternal (%lld, %i)\n", offset
, mode
);
1573 n
= fseek (fd
, offset
, mode
);
1579 FileSource::ReadInternal (void *buf
, guint32 n
)
1585 LOG_PIPELINE_ERROR ("FileSource::ReadInternal (%p, %u): File not open.\n", buf
, n
);
1590 nread
= fread (buf
, 1, n
, fd
);
1592 LOG_PIPELINE_EX ("FileSource::ReadInternal (0x????????, %i), nread: %i\n", (int) n
, (int) nread
);
1598 FileSource::PeekInternal (void *buf
, guint32 n
)
1602 result
= ReadSome (buf
, n
);
1604 Seek (-result
, SEEK_CUR
);
1606 LOG_PIPELINE_EX ("FileSource<%i>::PeekInternal (%p, %i), GetPosition (): %lld [Done]\n", GET_OBJ_ID (this), buf
, n
, GetPosition ());
1624 ProgressiveSource::ProgressiveSource (Media
*media
, const char *uri
) : FileSource (media
, true)
1630 this->uri
= g_strdup (uri
);
1634 ProgressiveSource::Dispose ()
1640 cancellable
->Cancel ();
1647 FileSource::Dispose ();
1651 ProgressiveSource::Initialize ()
1653 MediaResult result
= MEDIA_SUCCESS
;
1654 Application
*application
;
1656 application
= GetDeployment ()->GetCurrentApplication ();
1658 g_return_val_if_fail (application
!= NULL
, MEDIA_FAIL
);
1659 g_return_val_if_fail (filename
== NULL
, MEDIA_FAIL
);
1660 g_return_val_if_fail (cancellable
== NULL
, MEDIA_FAIL
);
1662 result
= FileSource::Initialize ();
1664 if (!MEDIA_SUCCEEDED (result
))
1667 write_fd
= fopen (filename
, "w");
1668 if (write_fd
== NULL
) {
1669 char *msg
= g_strdup_printf ("Could not open a write handle to the file '%s'\n", filename
);
1670 ReportErrorOccurred (msg
);
1675 // unlink the file right away so that it'll be deleted even if we crash.
1676 if (moonlight_flags
& RUNTIME_INIT_KEEP_MEDIA
) {
1677 printf ("Moonlight: The media file %s will not deleted.\n", filename
);
1682 cancellable
= new Cancellable ();
1683 Uri
*u
= new Uri ();
1684 if (u
->Parse (uri
)) {
1685 application
->GetResource (NULL
, u
, notify_func
, data_write
, MediaPolicy
, cancellable
, (gpointer
) this);
1687 result
= MEDIA_FAIL
;
1688 char *msg
= g_strdup_printf ("Could not parse the uri '%s'", uri
);
1689 ReportErrorOccurred (msg
);
1698 ProgressiveSource::notify_func (NotifyType type
, gint64 args
, void *closure
)
1700 g_return_if_fail (closure
!= NULL
);
1701 ((ProgressiveSource
*) closure
)->Notify (type
, args
);
1705 ProgressiveSource::Notify (NotifyType type
, gint64 args
)
1707 LOG_PIPELINE ("ProgressiveSource::Notify (%i = %s, %" G_GINT64_FORMAT
")\n",
1709 type
== ::NotifySize
? "NotifySize" :
1710 (type
== NotifyCompleted
? "NotifyCompleted" :
1711 (type
== NotifyFailed
? "NotifyFailed" :
1712 (type
== NotifyStarted
? "NotifyStarted" :
1713 (type
== NotifyProgressChanged
? "NotifyProgressChanged" : "unknown")))),
1720 case NotifyCompleted
:
1721 DownloadComplete ();
1727 case NotifyProgressChanged
:
1734 ProgressiveSource::data_write (void *data
, gint32 offset
, gint32 n
, void *closure
)
1736 g_return_if_fail (closure
!= NULL
);
1737 ((ProgressiveSource
*) closure
)->DataWrite (data
, offset
, n
);
1741 ProgressiveSource::DataWrite (void *buf
, gint32 offset
, gint32 n
)
1744 Media
*media
= GetMediaReffed ();
1746 LOG_PIPELINE ("ProgressiveSource::DataWrite (%p, %i, %i) media: %p, filename: %s\n", buf
, offset
, n
, media
, filename
);
1748 g_return_if_fail (write_fd
!= NULL
);
1751 // We've got the entire file, update the size
1752 size
= write_pos
; // Since this method is the only method that writes to write_pos, and we're not reentrant, there is no need to lock here.
1754 // Close our write handle, we won't write more now
1760 nwritten
= fwrite (buf
, 1, n
, write_fd
);
1764 write_pos
+= nwritten
;
1770 media
->ReportDownloadProgress ((double) (offset
+ n
) / (double) size
);
1776 ProgressiveSource::NotifySize (gint64 size
)
1778 LOG_PIPELINE ("ProgressiveSource::NotifySize (%lld)\n", size
);
1786 ProgressiveSource::DownloadComplete ()
1788 MediaResult result
= MEDIA_SUCCESS
;
1789 Media
*media
= GetMediaReffed ();
1791 LOG_PIPELINE ("ProgressiveSource::DownloadComplete ()\n");
1794 if (write_pos
!= size
&& size
!= -1) { // what happend here?
1795 LOG_PIPELINE ("ProgressiveSource::DownloadComplete (): the downloaded size (%" G_GINT64_FORMAT
") != the reported size (%" G_GINT64_FORMAT
")\n", write_pos
, size
);
1798 this->size
= write_pos
;
1800 // Close our write handle, we won't write more now
1805 if (!MEDIA_SUCCEEDED (result
))
1806 ReportErrorOccurred (result
);
1809 media
->ReportDownloadProgress (1.0);
1816 ProgressiveSource::DownloadFailed ()
1818 LOG_PIPELINE ("ProgressiveSource::DownloadFailed ().\n");
1820 ReportErrorOccurred (new ErrorEventArgs (MediaError
, 4001, "AG_E_NETWORK_ERROR"));
1824 ProgressiveSource::CloseWriteFile ()
1826 if (write_fd
== NULL
)
1837 MemorySource::MemorySource (Media
*media
, void *memory
, gint32 size
, gint64 start
, bool owner
)
1838 : IMediaSource (Type::MEMORYSOURCE
, media
)
1840 this->memory
= memory
;
1842 this->start
= start
;
1844 this->owner
= owner
;
1847 MemorySource::~MemorySource ()
1854 MemorySource::SeekInternal (gint64 offset
, int mode
)
1860 real_offset
= offset
- start
;
1861 if (real_offset
< 0 || real_offset
>= size
)
1866 if (pos
+ offset
> size
|| pos
+ offset
< 0)
1871 if (size
- offset
> size
|| size
- offset
< 0)
1873 pos
= size
- offset
;
1882 MemorySource::ReadInternal (void *buffer
, guint32 n
)
1884 guint32 k
= MIN (n
, size
- pos
);
1885 memcpy (buffer
, ((char*) memory
) + pos
, k
);
1891 MemorySource::PeekInternal (void *buffer
, guint32 n
)
1893 gint64 start
= this->start
+ pos
;
1895 if (this->start
> start
)
1898 if ((this->start
+ size
) < (start
+ n
))
1901 memcpy (buffer
, ((char*) memory
) + this->start
- start
, n
);
1909 MediaClosure::MediaClosure (Media
*media
, MediaCallback
*callback
, MediaCallback
*finished
, EventObject
*context
)
1910 : EventObject (Type::MEDIACLOSURE
, true)
1912 g_return_if_fail (callback
!= NULL
);
1913 g_return_if_fail (media
!= NULL
);
1915 result
= MEDIA_INVALID
;
1916 this->callback
= callback
;
1917 this->finished
= finished
;
1918 this->context
= context
;
1920 this->context
->ref ();
1921 this->media
= media
;
1923 this->media
->ref ();
1926 MediaClosure::MediaClosure (Media
*media
, MediaCallback
*callback
, EventObject
*context
)
1927 : EventObject (Type::MEDIACLOSURE
, true)
1929 g_return_if_fail (callback
!= NULL
);
1930 g_return_if_fail (media
!= NULL
);
1932 result
= MEDIA_INVALID
;
1933 this->callback
= callback
;
1934 this->finished
= NULL
;
1935 this->context
= context
;
1937 this->context
->ref ();
1938 this->media
= media
;
1940 this->media
->ref ();
1944 MediaClosure::Dispose ()
1959 EventObject::Dispose ();
1963 MediaClosure::Call ()
1966 result
= callback (this);
1968 result
= MEDIA_NO_CALLBACK
;
1976 * MediaDisposeObjectClosure
1978 MediaDisposeObjectClosure::MediaDisposeObjectClosure (Media
*media
, MediaCallback
*callback
, EventObject
*context
)
1979 : MediaClosure (media
, callback
, context
)
1984 MediaDisposeObjectClosure::Dispose ()
1986 if (!CallExecuted ()) {
1987 // we haven't been executed. do it now.
1989 LOG_PIPELINE ("MediaDisposeObjectClosure::~MediaDisposeObjectClosure (): callback hasn't been executed, we'll do it now.\n");
1994 MediaClosure::Dispose ();
2000 MediaSeekClosure::MediaSeekClosure (Media
*media
, MediaCallback
*callback
, IMediaDemuxer
*context
, guint64 pts
)
2001 : MediaClosure (media
, callback
, context
)
2007 * MediaReportSeekCompletedClosure
2010 MediaReportSeekCompletedClosure::MediaReportSeekCompletedClosure (Media
*media
, MediaCallback
*callback
, IMediaDemuxer
*context
, guint64 pts
)
2011 : MediaClosure (media
, callback
, context
)
2013 g_return_if_fail (context
!= NULL
);
2018 MediaReportSeekCompletedClosure::~MediaReportSeekCompletedClosure ()
2023 MediaReportSeekCompletedClosure::Dispose ()
2025 MediaClosure::Dispose ();
2029 * MediaGetFrameClosure
2032 MediaGetFrameClosure::MediaGetFrameClosure (Media
*media
, MediaCallback
*callback
, IMediaDemuxer
*context
, IMediaStream
*stream
)
2033 : MediaClosure (media
, callback
, context
)
2035 this->stream
= NULL
;
2037 g_return_if_fail (context
!= NULL
);
2038 g_return_if_fail (stream
!= NULL
);
2040 this->stream
= stream
;
2041 // this->stream->ref ();
2043 //fprintf (stderr, "MediaGetFrameClosure::MediaGetFrameClosure () id: %i\n", GetId ());
2046 MediaGetFrameClosure::~MediaGetFrameClosure ()
2048 //fprintf (stderr, "MediaGetFrameClosure::~MediaGetFrameClosure () id: %i\n", GetId ());
2052 MediaGetFrameClosure::Dispose ()
2055 // stream->unref ();
2059 MediaClosure::Dispose ();
2060 //fprintf (stderr, "MediaGetFrameClosure::Dispose () id: %i\n", GetId ());
2067 IMediaStream::IMediaStream (Type::Kind kind
, Media
*media
) : IMediaObject (kind
, media
)
2071 extra_data_size
= 0;
2083 input_ended
= false;
2084 output_ended
= false;
2086 first_pts
= G_MAXUINT64
; // The first pts in the stream, initialized to G_MAXUINT64
2087 last_popped_pts
= G_MAXUINT64
; // The pts of the last frame returned, initialized to G_MAXUINT64
2088 last_enqueued_pts
= G_MAXUINT64
; // The pts of the last frame enqueued, initialized to G_MAXUINT64
2089 last_available_pts
= 0; // The pts of the last available frame, initialized to 0
2093 IMediaStream::Dispose ()
2096 IMediaDecoder
*d
= decoder
;
2101 g_free (extra_data
);
2107 IMediaObject::Dispose ();
2111 IMediaStream::CreateCodec (int codec_id
)
2114 case CODEC_WMV1
: return g_strdup ("wmv1");
2115 case CODEC_WMV2
: return g_strdup ("wmv2");
2116 case CODEC_WMV3
: return g_strdup ("wmv3");
2117 case CODEC_WMVA
: return g_strdup ("wmva");
2118 case CODEC_WVC1
: return g_strdup ("vc1");
2119 case CODEC_RGBA
: return g_strdup ("rgba");
2120 case CODEC_YV12
: return g_strdup ("yv12");
2121 case CODEC_MP3
: return g_strdup ("mp3");
2122 case CODEC_WMAV1
: return g_strdup ("wmav1");
2123 case CODEC_WMAV2
: return g_strdup ("wmav2");
2124 case CODEC_WMAV3
: return g_strdup ("wmav3");
2125 case CODEC_PCM
: return g_strdup ("pcm");
2127 g_warning ("IMediaStream::CreateCodec (%i): Not implemented.\n", codec_id
);
2129 /* This algorithm needs testing.
2132 int a = (codec_id & 0x000000FF);
2133 int b = (codec_id & 0x0000FF00) >> 8;
2134 int c = (codec_id & 0x00FF0000) >> 16;
2135 int d = (codec_id & 0xFF000000) >> 24;
2137 size = (a != 0) + (b != 0) + (c != 0) + (d != 0);
2139 g_return_val_if_fail (size >= 0 && size <= 4, g_strdup (""));
2141 result = (char *) g_malloc (size + 1);
2144 result [current++] = (char) a;
2146 result [current++] = (char) b;
2148 result [current++] = (char) c;
2150 result [current++] = (char) d;
2151 result [current] = 0;
2153 return g_strdup ("<unknown>");
2159 IMediaStream::IsQueueEmpty ()
2161 return queue
.IsEmpty ();
2165 IMediaStream::GetStreamTypeName ()
2167 switch (GetType ()) {
2168 case MediaTypeVideo
: return "Video";
2169 case MediaTypeAudio
: return "Audio";
2170 case MediaTypeMarker
: return "Marker";
2171 default: return "Unknown";
2176 IMediaStream::ReportSeekCompleted ()
2179 if (decoder
!= NULL
)
2180 decoder
->ReportSeekCompleted ();
2184 IMediaStream::GetDemuxer ()
2187 IMediaDemuxer
*result
;
2192 media
= GetMediaReffed ();
2194 g_return_val_if_fail (media
!= NULL
, NULL
);
2196 result
= media
->GetDemuxer ();
2204 IMediaStream::GetDecoder ()
2210 IMediaStream::SetDecoder (IMediaDecoder
*value
)
2220 IMediaStream::GetOutputEnded ()
2222 return output_ended
;
2226 IMediaStream::SetOutputEnded (bool value
)
2228 output_ended
= value
;
2232 IMediaStream::GetInputEnded ()
2238 IMediaStream::SetInputEnded (bool value
)
2240 input_ended
= value
;
2241 if (GetDecoder () != NULL
)
2242 GetDecoder ()->ReportInputEnded ();
2246 IMediaStream::GetBufferedSize ()
2251 if (first_pts
== G_MAXUINT64
|| last_enqueued_pts
== G_MAXUINT64
)
2253 else if (last_popped_pts
== G_MAXUINT64
)
2254 result
= last_enqueued_pts
- first_pts
;
2256 result
= last_enqueued_pts
- last_popped_pts
;
2259 LOG_BUFFERING ("IMediaStream::GetBufferedSize (): id: %i, codec: %s, first_pts: %" G_GUINT64_FORMAT
" ms, last_popped_pts: %" G_GUINT64_FORMAT
" ms, last_enqueued_pts: %llu ms, result: %llu ms\n",
2260 GET_OBJ_ID (this), codec
, MilliSeconds_FromPts (first_pts
), MilliSeconds_FromPts (last_popped_pts
), MilliSeconds_FromPts (last_enqueued_pts
), MilliSeconds_FromPts (result
));
2267 #define TO_MS(x) (MilliSeconds_FromPts (x) == 1844674407370955ULL ? -1 : MilliSeconds_FromPts (x))
2270 IMediaStream::PrintBufferInformation ()
2272 guint64 buffer_size
= GetBufferedSize ();
2274 printf (" <%s: ", codec
);
2276 if (GetSelected ()) {
2277 printf ("size: %.4llu, first: %.4lli, last popped: %.4lli, last enq: %.4lli, frames enq: %i>",
2278 TO_MS (buffer_size
), TO_MS (first_pts
), TO_MS (last_popped_pts
),
2279 TO_MS (last_enqueued_pts
), queue
.Length ());
2281 printf ("(not selected) >");
2287 IMediaStream::EnqueueFrame (MediaFrame
*frame
)
2290 Media
*media
= GetMediaReffed ();
2292 g_return_if_fail (media
!= NULL
);
2293 g_return_if_fail (media
->InMediaThread ());
2296 if (first_pts
== G_MAXUINT64
)
2297 first_pts
= frame
->pts
;
2299 LOG_PIPELINE ("IMediaStream::EnqueueFrame (%p) %s %" G_GUINT64_FORMAT
" ms\n", frame
, frame
? frame
->stream
->GetStreamTypeName () : "", frame
? MilliSeconds_FromPts (frame
->pts
) : 0);
2302 if (last_enqueued_pts
> frame
->pts
&& last_enqueued_pts
!= G_MAXUINT64
&& frame
->event
!= FrameEventEOF
&& frame
->buflen
> 0) {
2303 g_warning ("IMediaStream::EnqueueFrame (): codec: %.5s, first_pts: %" G_GUINT64_FORMAT
" ms, last_popped_pts: %" G_GUINT64_FORMAT
" ms, last_enqueued_pts: %llu ms, "
2304 "buffer: %" G_GUINT64_FORMAT
" ms, frame: %p, frame->buflen: %i, frame->pts: %" G_GUINT64_FORMAT
" ms (the last enqueued frame's pts is below the current frame's pts)\n",
2305 codec
, MilliSeconds_FromPts (first_pts
), MilliSeconds_FromPts (last_popped_pts
), MilliSeconds_FromPts (last_enqueued_pts
),
2306 MilliSeconds_FromPts (last_popped_pts
!= G_MAXUINT64
? last_enqueued_pts
- last_popped_pts
: last_enqueued_pts
), frame
, frame
->buflen
, MilliSeconds_FromPts (frame
->pts
));
2310 last_enqueued_pts
= frame
->pts
;
2311 first
= queue
.LinkedList ()->Length () == 0;
2312 queue
.LinkedList ()->Append (new StreamNode (frame
));
2315 SetLastAvailablePts (frame
->pts
);
2318 EmitSafe (FirstFrameEnqueuedEvent
);
2324 LOG_BUFFERING ("IMediaStream::EnqueueFrame (): codec: %.5s, first: %i, first_pts: %" G_GUINT64_FORMAT
" ms, last_popped_pts: %" G_GUINT64_FORMAT
" ms, last_enqueued_pts: %" G_GUINT64_FORMAT
" ms, buffer: %" G_GUINT64_FORMAT
" ms, frame: %p, frame->buflen: %i\n",
2325 codec
, first
, MilliSeconds_FromPts (first_pts
), MilliSeconds_FromPts (last_popped_pts
), MilliSeconds_FromPts (last_enqueued_pts
),
2326 MilliSeconds_FromPts (last_popped_pts
!= G_MAXUINT64
? last_enqueued_pts
- last_popped_pts
: last_enqueued_pts
- first_pts
), frame
, frame
->buflen
);
2330 IMediaStream::PopFrame ()
2332 MediaFrame
*result
= NULL
;
2333 StreamNode
*node
= NULL
;
2335 // We use the queue lock to synchronize access to
2336 // last_popped_pts/last_enqueued_pts/first_pts
2339 node
= (StreamNode
*) queue
.LinkedList ()->First ();
2341 result
= node
->GetFrame ();
2343 queue
.LinkedList ()->Remove (node
);
2344 last_popped_pts
= result
->pts
;
2348 LOG_BUFFERING ("IMediaStream::PopFrame (): codec: %.5s, first_pts: %" G_GUINT64_FORMAT
" ms, last_popped_pts: %" G_GUINT64_FORMAT
" ms, last_enqueued_pts: %llu ms, buffer: %llu ms, frame: %p, frame->buflen: %i\n",
2349 codec
, MilliSeconds_FromPts (first_pts
), MilliSeconds_FromPts (last_popped_pts
), MilliSeconds_FromPts (last_enqueued_pts
),
2350 MilliSeconds_FromPts (last_popped_pts
!= G_MAXUINT64
? last_enqueued_pts
- last_popped_pts
: last_enqueued_pts
), result
, result
? result
->buflen
: 0);
2352 if (!input_ended
&& !output_ended
&& result
!= NULL
) {
2353 IMediaDemuxer
*demuxer
= GetDemuxer ();
2354 if (demuxer
!= NULL
)
2355 demuxer
->FillBuffers ();
2362 IMediaStream::ClearQueue ()
2364 LOG_BUFFERING ("IMediaStream::ClearQueue ()\n");
2366 queue
.LinkedList ()->Clear (true);
2367 first_pts
= G_MAXUINT64
;
2368 last_popped_pts
= G_MAXUINT64
;
2369 last_enqueued_pts
= G_MAXUINT64
;
2374 IMediaStream::SetSelected (bool value
)
2376 Media
*media
= GetMediaReffed ();
2380 if (media
->GetDemuxer ())
2381 media
->GetDemuxer ()->UpdateSelected (this);
2387 * IMediaStream.StreamNode
2390 IMediaStream::StreamNode::StreamNode (MediaFrame
*f
)
2396 IMediaStream::StreamNode::~StreamNode ()
2405 IMediaDemuxer::IMediaDemuxer (Type::Kind kind
, Media
*media
, IMediaSource
*source
) : IMediaObject (kind
, media
)
2407 this->source
= source
;
2408 this->source
->ref ();
2413 pending_stream
= NULL
;
2416 IMediaDemuxer::IMediaDemuxer (Type::Kind kind
, Media
*media
)
2417 : IMediaObject (kind
, media
)
2424 pending_stream
= NULL
;
2428 IMediaDemuxer::Dispose ()
2430 if (streams
!= NULL
) {
2431 IMediaStream
**tmp
= streams
;
2432 int stream_count
= this->stream_count
;
2434 for (int i
= 0; i
< stream_count
; i
++) {
2435 tmp
[i
]->Dispose ();
2444 if (pending_stream
!= NULL
) {
2445 pending_stream
->unref ();
2446 pending_stream
= NULL
;
2449 IMediaObject::Dispose ();
2453 IMediaDemuxer::OpenCallback (MediaClosure
*closure
)
2455 IMediaDemuxer
*demuxer
;
2457 LOG_PIPELINE ("IMediaDemuxer::OpenCallback (%p)\n", closure
);
2459 demuxer
= (IMediaDemuxer
*) closure
->GetContext ();
2460 demuxer
->OpenDemuxerAsync ();
2462 return MEDIA_SUCCESS
;
2466 IMediaDemuxer::EnqueueOpen ()
2468 MediaClosure
*closure
;
2469 Media
*media
= GetMediaReffed ();
2471 LOG_PIPELINE ("IMediaDemuxer::EnqueueOpen ()\n");
2473 closure
= new MediaClosure (media
, OpenCallback
, this);
2474 media
->EnqueueWork (closure
, false);
2480 IMediaDemuxer::ReportOpenDemuxerCompleted ()
2482 Media
*media
= GetMediaReffed ();
2484 LOG_PIPELINE ("IMediaDemuxer::ReportDemuxerOpenCompleted () media: %p\n", media
);
2489 // Media might be null if we got disposed for some reason.
2493 media
->ReportOpenDemuxerCompleted ();
2498 IMediaDemuxer::ReportGetFrameProgress (double progress
)
2500 LOG_PIPELINE ("IMediaDemuxer::ReportGetFrameProgress (%f)\n", progress
);
2504 IMediaDemuxer::ReportSwitchMediaStreamCompleted (IMediaStream
*stream
)
2506 LOG_PIPELINE ("IMediaDemuxer::ReportSwitchMediaStreamCompleted (%p)\n", stream
);
2510 IMediaDemuxer::ReportGetDiagnosticCompleted (MediaStreamSourceDiagnosticKind kind
, gint64 value
)
2512 LOG_PIPELINE ("IMediaDemuxer::ReportGetDiagnosticCompleted (%i, %lld)\n", kind
, value
);
2516 IMediaDemuxer::ReportGetFrameCompleted (MediaFrame
*frame
)
2518 IMediaDecoder
*decoder
;
2520 g_return_if_fail (frame
== NULL
|| (frame
!= NULL
&& frame
->stream
!= NULL
));
2521 g_return_if_fail (pending_stream
!= NULL
); // we must be waiting for a frame ...
2523 LOG_PIPELINE ("IMediaDemuxer::ReportGetFrameCompleted (%p) %i %s %llu ms\n", frame
, GET_OBJ_ID (this), frame
? frame
->stream
->GetStreamTypeName () : "", frame
? MilliSeconds_FromPts (frame
->pts
) : (guint64
) -1);
2525 if (frame
== NULL
) {
2526 LOG_PIPELINE ("IMediaDemuxer::ReportGetFrameCompleted (%p): input end signaled for %s stream.\n", frame
, pending_stream
->GetStreamTypeName ());
2527 // No more data for this stream
2528 pending_stream
->SetInputEnded (true);
2529 } else if (!frame
->stream
->IsDisposed ()) {
2530 decoder
= frame
->stream
->GetDecoder ();
2531 decoder
->DecodeFrameAsync (frame
);
2534 pending_stream
->unref ();
2535 pending_stream
= NULL
; // not waiting for anything more
2537 // enqueue some more
2542 IMediaDemuxer::ReportSeekCompletedCallback (MediaClosure
*c
)
2544 MediaReportSeekCompletedClosure
*closure
= (MediaReportSeekCompletedClosure
*) c
;
2545 IMediaDemuxer
*demuxer
;
2547 g_return_val_if_fail (closure
!= NULL
, MEDIA_FAIL
);
2548 g_return_val_if_fail (closure
->GetContext () != NULL
, MEDIA_FAIL
);
2550 demuxer
= (IMediaDemuxer
*) closure
->GetContext ();
2551 demuxer
->ReportSeekCompleted (closure
->GetPts ());
2553 return MEDIA_SUCCESS
;
2557 IMediaDemuxer::EnqueueReportSeekCompleted (guint64 pts
)
2559 Media
*media
= GetMediaReffed ();
2560 MediaClosure
*closure
= new MediaReportSeekCompletedClosure (media
, ReportSeekCompletedCallback
, this, pts
);
2561 media
->EnqueueWork (closure
);
2567 IMediaDemuxer::ReportSeekCompleted (guint64 pts
)
2569 Media
*media
= GetMediaReffed ();
2571 LOG_PIPELINE ("IMediaDemuxer::ReportSeekCompleted (%llu)\n", pts
);
2573 g_return_if_fail (media
!= NULL
);
2575 if (!media
->InMediaThread ()) {
2576 EnqueueReportSeekCompleted (pts
);
2581 for (int i
= 0; i
< GetStreamCount (); i
++) {
2582 IMediaStream
*stream
= GetStream (i
);
2587 stream
->ReportSeekCompleted ();
2590 media
->ReportSeekCompleted (pts
);
2597 IMediaDemuxer::OpenDemuxerAsync ()
2599 g_return_if_fail (opened
== false);
2603 OpenDemuxerAsyncInternal ();
2607 IMediaDemuxer::GetFrameCallback (MediaClosure
*c
)
2609 MediaGetFrameClosure
*closure
= (MediaGetFrameClosure
*) c
;
2610 IMediaDemuxer
*demuxer
;
2612 g_return_val_if_fail (closure
!= NULL
, MEDIA_FAIL
);
2613 g_return_val_if_fail (closure
->GetStream () != NULL
, MEDIA_FAIL
);
2614 g_return_val_if_fail (closure
->GetContext () != NULL
, MEDIA_FAIL
);
2616 demuxer
= (IMediaDemuxer
*) closure
->GetContext ();
2617 demuxer
->GetFrameAsync (closure
->GetStream ());
2619 return MEDIA_SUCCESS
;
2623 IMediaDemuxer::EnqueueGetFrame (IMediaStream
*stream
)
2625 g_return_if_fail (pending_stream
== NULL
); // we can't be waiting for another frame.
2627 Media
*media
= GetMediaReffed ();
2628 MediaClosure
*closure
= new MediaGetFrameClosure (media
, GetFrameCallback
, this, stream
);
2629 media
->EnqueueWork (closure
);
2635 IMediaDemuxer::GetFrameAsync (IMediaStream
*stream
)
2637 Media
*media
= GetMediaReffed ();
2639 g_return_if_fail (stream
!= NULL
);
2640 g_return_if_fail (media
!= NULL
);
2641 g_return_if_fail (pending_stream
== NULL
); // we can't be waiting for another frame.
2643 LOG_PIPELINE ("IMediaDemuxer::GetFrameAsync (%p) %s InMediaThread: %i\n", stream
, stream
->GetStreamTypeName (), media
->InMediaThread ());
2645 if (!media
->InMediaThread ()) {
2646 EnqueueGetFrame (stream
);
2650 pending_stream
= stream
;
2651 pending_stream
->ref ();
2652 GetFrameAsyncInternal (stream
);
2657 IMediaDemuxer::SeekCallback (MediaClosure
*closure
)
2659 MediaSeekClosure
*seek
= (MediaSeekClosure
*) closure
;
2660 seek
->GetDemuxer ()->SeekAsync (seek
->GetPts ());
2661 return MEDIA_SUCCESS
;
2665 IMediaDemuxer::EnqueueSeek (guint64 pts
)
2667 Media
*media
= GetMediaReffed ();
2668 MediaSeekClosure
*closure
;
2670 g_return_if_fail (media
!= NULL
);
2672 closure
= new MediaSeekClosure (media
, SeekCallback
, this, pts
);
2673 media
->EnqueueWork (closure
, true);
2679 IMediaDemuxer::SeekAsync (guint64 pts
)
2681 Media
*media
= GetMediaReffed ();
2683 g_return_if_fail (media
!= NULL
);
2685 LOG_PIPELINE ("IMediaDemuxer::SeekAsync (%llu)\n", pts
);
2687 if (!media
->InMediaThread ()) {
2690 SeekAsyncInternal (pts
);
2697 IMediaDemuxer::FillBuffersCallback (MediaClosure
*closure
)
2699 IMediaDemuxer
*demuxer
= (IMediaDemuxer
*) closure
->GetContext ();
2700 demuxer
->FillBuffersInternal ();
2701 return MEDIA_SUCCESS
;
2705 IMediaDemuxer::FillBuffers ()
2707 Media
*media
= GetMediaReffed ();
2708 MediaClosure
*closure
;
2710 g_return_if_fail (media
!= NULL
);
2712 closure
= new MediaClosure (media
, FillBuffersCallback
, this);
2713 media
->EnqueueWork (closure
);
2719 IMediaDemuxer::FillBuffersInternal ()
2721 IMediaStream
*stream
;
2722 IMediaStream
*request_stream
= NULL
;
2723 guint64 min_buffered_size
= G_MAXUINT64
;
2724 MediaResult result
= MEDIA_SUCCESS
;
2725 Media
*media
= GetMediaReffed ();
2726 guint64 buffering_time
= 0;
2727 guint64 buffered_size
= 0;
2729 int media_streams
= 0;
2731 LOG_BUFFERING ("IMediaDemuxer::FillBuffersInternal (), %i %s buffering time: %llu = %llu ms, pending_stream: %i %s\n", GET_OBJ_ID (this), GetTypeName (), buffering_time
, MilliSeconds_FromPts (buffering_time
), GET_OBJ_ID (pending_stream
), pending_stream
? pending_stream
->GetStreamTypeName () : "NULL");
2733 // If we're waiting for something, there's nothing to do here.
2734 if (pending_stream
!= NULL
)
2737 // Find the stream with the smallest buffered size, and request a frame from that stream.
2738 g_return_if_fail (media
!= NULL
);
2740 buffering_time
= media
->GetBufferingTime ();
2743 for (int i
= 0; i
< GetStreamCount (); i
++) {
2744 IMediaDecoder
*decoder
= NULL
;
2746 stream
= GetStream (i
);
2747 if (!stream
->GetSelected ())
2750 if (stream
->GetType () != MediaTypeVideo
&&
2751 stream
->GetType () != MediaTypeAudio
)
2755 if (stream
->GetOutputEnded ()) {
2757 continue; // this stream has ended.
2760 decoder
= stream
->GetDecoder ();
2761 if (decoder
== NULL
) {
2762 fprintf (stderr
, "IMediaDemuxer::FillBuffersInternal () %s stream has no decoder (id: %i refcount: %i)\n", stream
->GetStreamTypeName (), GET_OBJ_ID (stream
), stream
->GetRefCount ());
2763 continue; // no decoder??
2766 buffered_size
= stream
->GetBufferedSize ();
2767 min_buffered_size
= MIN (min_buffered_size
, buffered_size
);
2769 if (buffered_size
>= buffering_time
)
2770 continue; // this stream has enough data buffered.
2772 if (!decoder
->IsDecoderQueueEmpty ())
2773 continue; // this stream is waiting for data to be decoded.
2775 if (buffered_size
<= min_buffered_size
)
2776 request_stream
= stream
;
2778 LOG_BUFFERING ("IMediaDemuxer::FillBuffersInternal (): codec: %s, stream id: %i, result: %i, buffered size: %" G_GUINT64_FORMAT
" ms, buffering time: %" G_GUINT64_FORMAT
" ms, last popped time: %llu ms\n",
2779 stream
->codec
, GET_OBJ_ID (stream
), result
, MilliSeconds_FromPts (buffered_size
), MilliSeconds_FromPts (buffering_time
), MilliSeconds_FromPts (stream
->GetLastPoppedPts ()));
2782 if (request_stream
!= NULL
) {
2783 LOG_BUFFERING ("IMediaDemuxer::FillBuffersInternal (): requesting frame from %s stream (%i), min_buffered_size: %" G_GUINT64_FORMAT
" ms\n", request_stream
->GetStreamTypeName (), GET_OBJ_ID (stream
), MilliSeconds_FromPts (min_buffered_size
));
2784 GetFrameAsync (request_stream
);
2787 if (media_streams
> 0) {
2788 if (ended
== media_streams
) {
2789 media
->ReportBufferingProgress (1.0);
2791 if (min_buffered_size
> 0 && buffering_time
> 0) {
2792 double progress
= ((double) min_buffered_size
/ (double) buffering_time
);
2793 media
->ReportBufferingProgress (progress
);
2800 LOG_BUFFERING ("IMediaDemuxer::FillBuffersInternal () [Done]. BufferedSize: %" G_GUINT64_FORMAT
" ms\n", MilliSeconds_FromPts (GetBufferedSize ()));
2804 IMediaDemuxer::GetBufferedSize ()
2806 guint64 result
= G_MAXUINT64
;
2807 IMediaStream
*stream
;
2809 for (int i
= 0; i
< GetStreamCount (); i
++) {
2810 stream
= GetStream (i
);
2811 if (!stream
->GetSelected ())
2814 if (stream
->GetType () != MediaTypeVideo
&& stream
->GetType () != MediaTypeAudio
)
2817 result
= MIN (result
, stream
->GetBufferedSize ());
2824 IMediaDemuxer::GetLastAvailablePts ()
2826 guint64 result
= G_MAXUINT64
;
2827 IMediaStream
*stream
;
2829 for (int i
= 0; i
< GetStreamCount (); i
++) {
2830 stream
= GetStream (i
);
2832 if (stream
== NULL
|| !stream
->GetSelected ())
2835 result
= MIN (result
, stream
->GetLastAvailablePts ());
2838 if (result
== G_MAXUINT64
)
2846 IMediaDemuxer::PrintBufferInformation ()
2848 printf ("Buffer: %lld", MilliSeconds_FromPts (GetBufferedSize ()));
2849 for (int i
= 0; i
< GetStreamCount (); i
++) {
2850 GetStream (i
)->PrintBufferInformation ();
2857 IMediaDemuxer::GetDuration ()
2860 for (int i
= 0; i
< GetStreamCount (); i
++)
2861 result
= MAX (result
, GetStream (i
)->duration
);
2866 IMediaDemuxer::GetStream (int index
)
2868 return (index
< 0 || index
>= stream_count
) ? NULL
: streams
[index
];
2875 MediaFrame::MediaFrame (IMediaStream
*stream
)
2876 : EventObject (Type::MEDIAFRAME
)
2880 g_return_if_fail (stream
!= NULL
);
2882 this->stream
= stream
;
2883 this->stream
->ref ();
2886 MediaFrame::MediaFrame (IMediaStream
*stream
, guint8
*buffer
, guint32 buflen
, guint64 pts
, bool keyframe
)
2887 : EventObject (Type::MEDIAFRAME
)
2891 g_return_if_fail (stream
!= NULL
);
2893 this->stream
= stream
;
2894 this->stream
->ref ();
2895 this->buffer
= buffer
;
2896 this->buflen
= buflen
;
2900 if (buflen
> 4 && false) {
2901 printf ("MediaFrame::MediaFrame () %s buffer: ", stream
->GetStreamTypeName ());
2902 for (int i
= 0; i
< 4; i
++)
2903 printf (" 0x%x", buffer
[i
]);
2909 AddState (MediaFrameKeyFrame
);
2913 MediaFrame::Initialize ()
2915 decoder_specific_data
= NULL
;
2927 for (int i
= 0; i
< 4; i
++) {
2938 MediaFrame::~MediaFrame ()
2943 MediaFrame::Dispose ()
2945 IMediaDecoder
*decoder
;
2949 // We can be called either on the main thread just before destruction
2950 // (in which case there are no races since the code which unreffed us
2951 // is the only code which knows about us), or at any time from the
2954 if (GetRefCount () != 0 && stream
!= NULL
) {
2955 media
= stream
->GetMediaReffed ();
2956 if (media
!= NULL
&& !media
->InMediaThread ()) {
2957 // if refcount != 0 we're not being called just before destruction, in which case we should
2958 // only be on the media thread.
2959 printf ("MediaFrame::Dispose (): this method should only be called from the media thread.\n");
2965 if (decoder_specific_data
!= NULL
&& stream
!= NULL
) {
2966 decoder
= stream
->GetDecoder ();
2967 if (decoder
!= NULL
)
2968 decoder
->Cleanup (this);
2981 EventObject::Dispose ();
2985 MediaFrame::SetSrcSlideY (int value
)
2991 MediaFrame::SetSrcSlideH (int value
)
2997 MediaFrame::SetSrcStride (int a
, int b
, int c
, int d
)
3006 MediaFrame::SetDataStride (guint8
* a
, guint8
* b
, guint8
* c
, guint8
* d
)
3008 data_stride
[0] = a
;
3009 data_stride
[1] = b
;
3010 data_stride
[2] = c
;
3011 data_stride
[3] = d
;
3015 * IMediaObject.EventData
3018 IMediaObject::EventData::EventData (int event_id
, EventHandler handler
, EventObject
*context
, bool invoke_on_main_thread
)
3020 this->event_id
= event_id
;
3021 this->handler
= handler
;
3022 this->context
= context
;
3023 this->context
->ref ();
3024 this->invoke_on_main_thread
= invoke_on_main_thread
;
3027 IMediaObject::EventData::~EventData ()
3034 * IMediaObject.EmitData
3037 IMediaObject::EmitData::EmitData (int event_id
, EventHandler handler
, EventObject
*context
, EventArgs
*args
)
3039 this->event_id
= event_id
;
3040 this->handler
= handler
;
3041 this->context
= context
;
3042 this->context
->ref ();
3048 IMediaObject::EmitData::~EmitData ()
3062 IMediaObject::IMediaObject (Type::Kind kind
, Media
*media
)
3063 : EventObject (kind
, true)
3065 this->media
= media
;
3067 this->media
->ref ();
3068 g_return_if_fail (media
!= NULL
);
3070 emit_on_main_thread
= NULL
;
3074 IMediaObject::Dispose ()
3078 // We can be called either on the main thread just before destruction
3079 // (in which case there are no races since the code which unreffed us
3080 // is the only code which knows about us), or at any time from the
3082 if (GetRefCount () != 0 && media
!= NULL
&& !media
->InMediaThread ()) {
3083 // if refcount != 0 we're not being called just before destruction, in which case we should
3084 // only be on the media thread.
3085 LOG_PIPELINE ("IMediaObject::Dispose (): this method should only be called from the media thread.\n");
3089 media_mutex
.Lock ();
3094 media_mutex
.Unlock ();
3096 event_mutex
.Lock ();
3099 if (emit_on_main_thread
!= NULL
) {
3100 delete emit_on_main_thread
;
3101 emit_on_main_thread
= NULL
;
3103 event_mutex
.Unlock ();
3105 EventObject::Dispose ();
3109 IMediaObject::InMediaThread ()
3113 Media
*media
= GetMediaReffed ();
3114 if (media
!= NULL
) {
3115 result
= media
->InMediaThread ();
3123 IMediaObject::AddSafeHandler (int event_id
, EventHandler handler
, EventObject
*context
, bool invoke_on_main_thread
)
3125 LOG_PIPELINE ("IMediaObject::AddSafeHandler (%i, %p, %p, %i)\n", event_id
, handler
, context
, invoke_on_main_thread
);
3128 if (!IsDisposed ()) {
3129 ed
= new EventData (event_id
, handler
, context
, invoke_on_main_thread
);
3130 event_mutex
.Lock ();
3132 events
= new List ();
3133 events
->Append (ed
);
3134 event_mutex
.Unlock ();
3139 IMediaObject::RemoveSafeHandlers (EventObject
*context
)
3144 event_mutex
.Lock ();
3145 if (events
!= NULL
) {
3146 ed
= (EventData
*) events
->First ();
3147 while (ed
!= NULL
) {
3148 next
= (EventData
*) ed
->next
;
3149 if (ed
->context
== context
)
3150 events
->Remove (ed
);
3154 event_mutex
.Unlock ();
3158 IMediaObject::EmitSafe (int event_id
, EventArgs
*args
)
3160 List
*emits
= NULL
; // The events to emit on this thread.
3167 // Create a list of all the events to emit
3168 // don't keep the lock while emitting.
3169 event_mutex
.Lock ();
3170 if (events
!= NULL
) {
3171 ed
= (EventData
*) events
->First ();
3172 while (ed
!= NULL
) {
3173 if (ed
->event_id
== event_id
) {
3174 emit
= new EmitData (event_id
, ed
->handler
, ed
->context
, args
);
3175 if (ed
->invoke_on_main_thread
) {
3176 if (emit_on_main_thread
== NULL
)
3177 emit_on_main_thread
= new List ();
3178 emit_on_main_thread
->Append (emit
);
3181 emits
= new List ();
3182 emits
->Append (emit
);
3185 ed
= (EventData
*) ed
->next
;
3188 event_mutex
.Unlock ();
3190 // emit the events to be emitted on this thread
3193 if (Surface::InMainThread ()) {
3194 // if we're already on the main thread,
3195 // we can the events to be emitted
3196 // on the main thread
3198 event_mutex
.Lock ();
3199 tmp
= emit_on_main_thread
;
3200 emit_on_main_thread
= NULL
;
3201 event_mutex
.Unlock ();
3204 AddTickCallSafe (EmitListCallback
);
3213 IMediaObject::EmitListMain ()
3218 event_mutex
.Lock ();
3219 list
= emit_on_main_thread
;
3220 emit_on_main_thread
= NULL
;
3221 event_mutex
.Unlock ();
3226 IMediaObject::EmitListCallback (EventObject
*obj
)
3228 IMediaObject
*media_obj
= (IMediaObject
*) obj
;
3229 media_obj
->EmitListMain ();
3233 IMediaObject::EmitList (List
*list
)
3240 emit
= (EmitData
*) list
->First ();
3241 while (emit
!= NULL
) {
3242 emit
->handler (this, emit
->args
, emit
->context
);
3243 emit
= (EmitData
*) emit
->next
;
3250 IMediaObject::GetMediaReffed ()
3253 media_mutex
.Lock ();
3257 media_mutex
.Unlock ();
3262 IMediaObject::ReportErrorOccurred (char const *message
)
3264 g_return_if_fail (media
!= NULL
);
3266 media
->ReportErrorOccurred (message
);
3270 IMediaObject::ReportErrorOccurred (MediaResult result
)
3272 g_return_if_fail (media
!= NULL
);
3274 media
->ReportErrorOccurred (result
);
3278 IMediaObject::ReportErrorOccurred (ErrorEventArgs
*args
)
3280 g_return_if_fail (media
!= NULL
);
3282 media
->ReportErrorOccurred (args
);
3286 IMediaObject::SetMedia (Media
*value
)
3288 media_mutex
.Lock ();
3294 media_mutex
.Unlock ();
3301 IMediaSource::IMediaSource (Type::Kind kind
, Media
*media
)
3302 : IMediaObject (kind
, media
)
3304 pthread_mutexattr_t attribs
;
3305 pthread_mutexattr_init (&attribs
);
3306 pthread_mutexattr_settype (&attribs
, PTHREAD_MUTEX_RECURSIVE
);
3307 pthread_mutex_init (&mutex
, &attribs
);
3308 pthread_mutexattr_destroy (&attribs
);
3310 pthread_cond_init (&condition
, NULL
);
3313 IMediaSource::~IMediaSource ()
3315 pthread_mutex_destroy (&mutex
);
3316 pthread_cond_destroy (&condition
);
3320 IMediaSource::Dispose ()
3322 IMediaObject::Dispose ();
3326 IMediaSource::Lock ()
3328 pthread_mutex_lock (&mutex
);
3332 IMediaSource::Unlock ()
3334 pthread_mutex_unlock (&mutex
);
3338 IMediaSource::ReadSome (void *buf
, guint32 n
)
3342 LOG_PIPELINE_EX ("IMediaSource<%i>::ReadSome (%p, %u)\n", GET_OBJ_ID (this), buf
, n
);
3346 result
= ReadInternal (buf
, n
);
3348 LOG_PIPELINE_EX ("IMediaSource<%i>::ReadSome (%p, %u) read %i, position: %lld\n", GET_OBJ_ID (this), buf
, n
, result
, GetPosition ());
3356 IMediaSource::ReadAll (void *buf
, guint32 n
)
3359 gint64 prev
= GetPosition ();
3360 gint64 avail
= GetLastAvailablePosition ();
3362 //printf ("IMediaSource::ReadAll (%p, %u), position: %lld\n", buf, n, prev);
3364 read
= ReadSome (buf
, n
);
3366 if ((gint64
) read
!= (gint64
) n
) {
3367 FileSource
*fs
= NULL
;
3369 if (GetType () == MediaSourceTypeFile
)
3370 fs
= (FileSource
*) this;
3371 g_warning ("IMediaSource::ReadInternal (%i): Read failed, read %i bytes. available size: %lld, size: %lld, pos: %lld, prev pos: %lld, position not available: %lld, feof: %i, ferror: %i, strerror: %s\n",
3372 n
, read
, avail
, GetSize (), GetPosition (), prev
, prev
+ n
, fs
? feof (fs
->fd
) : -1, fs
? ferror (fs
->fd
) : -1, fs
? strerror (ferror (fs
->fd
)) : "<N/A>");
3373 print_stack_trace ();
3376 LOG_PIPELINE_EX ("IMediaSource<%d>::ReadAll (%p, %u), read: %d [Done].\n", GET_OBJ_ID (this), buf
, n
, read
);
3378 return (gint64
) read
== (gint64
) n
;
3382 IMediaSource::Peek (void *buf
, guint32 n
)
3389 read
= PeekInternal (buf
, n
);
3390 result
= read
== (gint64
) n
;
3394 LOG_PIPELINE ("IMediaSource::Peek (%p, %u): peek result: %i, read %lld bytes.\n", buf
, n
, result
, read
);
3400 IMediaSource::Seek (gint64 offset
, int mode
)
3402 LOG_PIPELINE ("IMediaSource<%d> (%s)::Seek (%lld, %d = %s)\n",
3403 GET_OBJ_ID (this), ToString (), offset
, mode
, mode
== SEEK_SET
? "SEEK_SET"
3404 : (mode
== SEEK_CUR
? "SEEK_CUR" : (mode
== SEEK_END
? "SEEK_END" : "<invalid value>")));
3408 result
= SeekInternal (offset
, mode
);
3414 IMediaSource::IsPositionAvailable (gint64 position
, bool *eof
)
3416 gint64 available
= GetLastAvailablePosition ();
3417 gint64 size
= GetSize ();
3421 if (size
!= -1 && size
< position
) {
3422 // Size is known and smaller than the requested position
3427 if (available
!= -1 && available
< position
) {
3428 // Not everything is available and the available position is smaller than the requested position
3433 if (size
== -1 && available
== -1) {
3434 // Size is not known, but everything is available??
3435 // This is probably due to a bug in the derived *Source class
3437 fprintf (stderr
, "Moonlight: media assert error (invalid source size), media playback errors will probably occur\n");
3445 IMediaSource::GetLastAvailablePosition ()
3449 result
= GetLastAvailablePositionInternal ();
3455 IMediaSource::GetPositionInternal ()
3457 // This method should be overridden (or never called for the classes which doesn't override it).
3458 g_warning ("IMediaSource (%s)::GetPositionInternal (): You hit a bug in moonlight, please attach gdb, get a stack trace and file bug.", GetTypeName ());
3459 print_stack_trace ();
3464 IMediaSource::SeekInternal (gint64 offset
, int mode
)
3466 g_warning ("IMediaSource (%s)::SeekInternal (%lld, %i): You hit a bug in moonlight, please attach gdb, get a stack trace and file bug.", GetTypeName (), offset
, mode
);
3467 print_stack_trace ();
3473 IMediaSource::ReadInternal (void *buffer
, guint32 n
)
3475 g_warning ("IMediaSource (%s)::ReadInternal (%p, %u): You hit a bug in moonlight, please attach gdb, get a stack trace and file bug.", GetTypeName (), buffer
, n
);
3476 print_stack_trace ();
3482 IMediaSource::PeekInternal (void *buffer
, guint32 n
)
3484 g_warning ("IMediaSource (%s)::PeekInternal (%p, %u): You hit a bug in moonlight, please attach gdb, get a stack trace and file bug.", GetTypeName (), buffer
, n
);
3485 print_stack_trace ();
3491 IMediaSource::GetSizeInternal ()
3493 g_warning ("IMediaSource (%s)::GetSizeInternal (): You hit a bug in moonlight, please attach gdb, get a stack trace and file bug.", GetTypeName ());
3494 print_stack_trace ();
3500 IMediaSource::GetPosition ()
3504 result
= GetPositionInternal ();
3510 IMediaSource::GetSize ()
3514 result
= GetSizeInternal ();
3524 IMediaDemuxer::SetStreams (IMediaStream
** streams
, int count
)
3526 this->streams
= streams
;
3527 this->stream_count
= count
;
3529 for (int i
= 0; i
< count
; i
++)
3530 this->streams
[i
]->ref ();
3534 IMediaDemuxer::AddStream (IMediaStream
*stream
)
3536 g_return_val_if_fail (stream
!= NULL
, -1);
3539 streams
= (IMediaStream
**) g_realloc (streams
, stream_count
* sizeof (IMediaStream
*));
3540 streams
[stream_count
- 1] = stream
;
3543 return stream_count
- 1;
3550 IMediaDecoder::IMediaDecoder (Type::Kind kind
, Media
*media
, IMediaStream
*stream
) : IMediaObject (kind
, media
)
3552 this->stream
= NULL
;
3554 g_return_if_fail (stream
!= NULL
);
3556 this->stream
= stream
;
3557 this->stream
->ref ();
3561 input_ended
= false;
3565 IMediaDecoder::Dispose ()
3567 if (stream
!= NULL
) {
3568 IMediaStream
*s
= stream
;
3577 IMediaObject::Dispose ();
3581 IMediaDecoder::ReportSeekCompleted ()
3584 input_ended
= false;
3589 IMediaDecoder::ReportInputEnded ()
3592 if (IsDecoderQueueEmpty ()) {
3598 IMediaDecoder::ReportDecodeFrameCompleted (MediaFrame
*frame
)
3600 LOG_PIPELINE ("IMediaDecoder::ReportDecodeFrameCompleted (%p) %s %llu ms\n", frame
, frame
? frame
->stream
->GetStreamTypeName () : "", frame
? MilliSeconds_FromPts (frame
->pts
) : 0);
3602 g_return_if_fail (frame
!= NULL
);
3603 g_return_if_fail (frame
->stream
!= NULL
);
3605 frame
->stream
->EnqueueFrame (frame
);
3606 frame
->stream
->GetDemuxer ()->FillBuffers ();
3608 if (input_ended
&& IsDecoderQueueEmpty ())
3613 IMediaDecoder::DecodeFrameCallback (MediaClosure
*closure
)
3616 IMediaDecoder
*decoder
= (IMediaDecoder
*) closure
->GetContext ();
3617 IMediaDecoder::FrameNode
*node
= (IMediaDecoder::FrameNode
*) decoder
->queue
.Pop ();
3620 decoder
->DecodeFrameAsync (node
->frame
);
3624 return MEDIA_SUCCESS
;
3628 IMediaDecoder::DecodeFrameAsync (MediaFrame
*frame
)
3632 LOG_PIPELINE ("IMediaDecoder::DecodeFrameAsync (%p) %s\n", frame
, (frame
&& frame
->stream
) ? frame
->stream
->GetStreamTypeName () : NULL
);
3637 media
= GetMediaReffed ();
3639 g_return_if_fail (frame
!= NULL
);
3640 g_return_if_fail (media
!= NULL
);
3642 if (!media
->InMediaThread ()) {
3643 MediaClosure
*closure
= new MediaClosure (media
, DecodeFrameCallback
, this);
3644 queue
.Push (new FrameNode (frame
));
3645 media
->EnqueueWork (closure
);
3650 DecodeFrameAsyncInternal (frame
);
3656 IMediaDecoder::OpenDecoderAsync ()
3658 LOG_PIPELINE ("IMediaDecoder::OpenDecoderAsync ()\n");
3660 g_return_if_fail (opening
== false);
3661 g_return_if_fail (opened
== false);
3664 OpenDecoderAsyncInternal ();
3668 IMediaDecoder::ReportOpenDecoderCompleted ()
3670 Media
*media
= GetMediaReffed ();
3672 LOG_PIPELINE ("IMediaDecoder::ReportOpenDecoderCompleted ()\n");
3677 g_return_if_fail (media
!= NULL
);
3679 media
->ReportOpenDecoderCompleted (this);
3687 IImageConverter::IImageConverter (Type::Kind kind
, Media
*media
, VideoStream
*stream
) : IMediaObject (kind
, media
)
3689 output_format
= MoonPixelFormatNone
;
3690 input_format
= MoonPixelFormatNone
;
3691 this->stream
= stream
;
3698 VideoStream::VideoStream (Media
*media
) : IMediaStream (Type::VIDEOSTREAM
, media
)
3701 bits_per_sample
= 0;
3708 VideoStream::VideoStream (Media
*media
, int codec_id
, guint32 width
, guint32 height
, guint64 duration
, gpointer extra_data
, guint32 extra_data_size
)
3709 : IMediaStream (Type::VIDEOSTREAM
, media
)
3712 bits_per_sample
= 0;
3715 this->height
= height
;
3716 this->width
= width
;
3717 this->duration
= duration
;
3718 this->codec_id
= codec_id
;
3719 this->codec
= CreateCodec (codec_id
);
3720 this->extra_data
= extra_data
;
3721 this->extra_data_size
= extra_data_size
;
3724 VideoStream::~VideoStream ()
3729 VideoStream::Dispose ()
3732 converter
->Dispose ();
3733 converter
->unref ();
3736 IMediaStream::Dispose ();
3740 * MediaMarkerFoundClosure
3743 MediaMarkerFoundClosure::MediaMarkerFoundClosure (Media
*media
, MediaCallback
*callback
, MediaElement
*context
)
3744 : MediaClosure (media
, callback
, context
)
3750 MediaMarkerFoundClosure::Dispose ()
3756 MediaClosure::Dispose ();
3760 MediaMarkerFoundClosure::SetMarker (MediaMarker
*marker
)
3763 this->marker
->unref ();
3764 this->marker
= marker
;
3766 this->marker
->ref ();
3773 MediaMarker::MediaMarker (const char *type
, const char *text
, guint64 pts
)
3774 : EventObject (Type::MEDIAMARKER
)
3776 this->type
= g_strdup (type
);
3777 this->text
= g_strdup (text
);
3781 MediaMarker::~MediaMarker ()
3791 MarkerStream::MarkerStream (Media
*media
) : IMediaStream (Type::MARKERSTREAM
, media
)
3797 MarkerStream::Dispose ()
3804 IMediaStream::Dispose ();
3808 MarkerStream::MarkerFound (MediaFrame
*frame
)
3810 LOG_PIPELINE ("MarkerStream::MarkerFound ().\n");
3812 if (GetDecoder () == NULL
) {
3813 LOG_PIPELINE ("MarkerStream::MarkerFound (): Got marker, but there's no decoder for the marker.\n");
3817 GetDecoder ()->DecodeFrameAsync (frame
);
3821 MarkerStream::FrameEnqueued ()
3825 LOG_PIPELINE ("MarkerStream::FrameEnqueued ().\n");
3827 frame
= PopFrame ();
3829 if (frame
== NULL
) {
3830 LOG_PIPELINE ("MarkerStream::FrameEnqueued (): No frame.\n");
3834 if (closure
!= NULL
) {
3835 closure
->SetMarker (frame
->marker
);
3837 closure
->SetMarker (NULL
);
3839 LOG_PIPELINE ("MarkerStream::FrameEnqueued (): No callback.\n");
3841 list
.Append (new MediaMarker::Node (frame
->marker
));
3849 MarkerStream::Pop ()
3851 MediaMarker
*result
= NULL
;
3852 MediaMarker::Node
*node
;
3855 node
= (MediaMarker::Node
*) list
.First ();
3857 result
= node
->marker
;
3867 MarkerStream::SetCallback (MediaMarkerFoundClosure
*closure
)
3870 this->closure
->unref ();
3871 this->closure
= closure
;
3873 this->closure
->ref ();
3879 MediaWork::MediaWork (MediaClosure
*c
)
3881 g_return_if_fail (c
!= NULL
);
3887 MediaWork::~MediaWork ()
3889 g_return_if_fail (closure
!= NULL
);
3896 * PassThroughDecoderInfo
3900 PassThroughDecoderInfo::Supports (const char *codec
)
3902 const char *video_fourccs
[] = { "yv12", "rgba", NULL
};
3903 const char *audio_fourccs
[] = { "pcm", NULL
};
3905 for (int i
= 0; video_fourccs
[i
] != NULL
; i
++)
3906 if (!strcmp (codec
, video_fourccs
[i
]))
3909 for (int i
= 0; audio_fourccs
[i
] != NULL
; i
++)
3910 if (!strcmp (codec
, audio_fourccs
[i
]))
3917 * PassThroughDecoder
3920 PassThroughDecoder::PassThroughDecoder (Media
*media
, IMediaStream
*stream
)
3921 : IMediaDecoder (Type::PASSTHROUGHDECODER
, media
, stream
)
3926 PassThroughDecoder::Dispose ()
3928 IMediaDecoder::Dispose ();
3932 PassThroughDecoder::OpenDecoderAsyncInternal ()
3934 const char *fourcc
= GetStream ()->GetCodec ();
3936 if (!strcmp (fourcc
, "yv12")) {
3937 SetPixelFormat (MoonPixelFormatYUV420P
);
3938 } else if (!strcmp (fourcc
, "rgba")) {
3939 SetPixelFormat (MoonPixelFormatRGBA32
);
3940 } else if (!strcmp (fourcc
, "pcm")) {
3941 // nothing to do here
3943 ReportErrorOccurred (g_strdup_printf ("Unknown fourcc: %s", fourcc
));
3947 ReportOpenDecoderCompleted ();
3951 PassThroughDecoder::DecodeFrameAsyncInternal (MediaFrame
*frame
)
3953 frame
->AddState (MediaFrameDecoded
);
3954 if (GetPixelFormat () == MoonPixelFormatYUV420P
) {
3955 VideoStream
*vs
= (VideoStream
*) GetStream ();
3957 frame
->width
= vs
->width
;
3958 frame
->height
= vs
->height
;
3960 frame
->data_stride
[0] = frame
->buffer
;
3961 frame
->data_stride
[1] = frame
->buffer
+ (frame
->width
*frame
->height
);
3962 frame
->data_stride
[2] = frame
->buffer
+ (frame
->width
*frame
->height
)+(frame
->width
/2*frame
->height
/2);
3963 frame
->buffer
= NULL
;
3964 frame
->srcStride
[0] = frame
->width
;
3965 frame
->srcSlideY
= frame
->width
;
3966 frame
->srcSlideH
= frame
->height
;
3968 frame
->AddState (MediaFramePlanar
);
3970 ReportDecodeFrameCompleted (frame
);
3978 NullDecoderInfo::Supports (const char *codec
)
3980 const char *video_fourccs
[] = { "wmv1", "wmv2", "wmv3", "wmva", "vc1", NULL
};
3981 const char *audio_fourccs
[] = { "wmav1","wmav2", "wmav3", "mp3", NULL
};
3983 for (int i
= 0; video_fourccs
[i
] != NULL
; i
++)
3984 if (!strcmp (codec
, video_fourccs
[i
]))
3987 for (int i
= 0; audio_fourccs
[i
] != NULL
; i
++)
3988 if (!strcmp (codec
, audio_fourccs
[i
]))
3999 NullDecoder::NullDecoder (Media
*media
, IMediaStream
*stream
) : IMediaDecoder (Type::NULLDECODER
, media
, stream
)
4003 prev_pts
= G_MAXUINT64
;
4007 NullDecoder::Dispose ()
4012 IMediaDecoder::Dispose ();
4016 NullDecoder::DecodeVideoFrame (MediaFrame
*frame
)
4018 // free encoded buffer and alloc a new one for our image
4019 g_free (frame
->buffer
);
4020 frame
->buflen
= logo_size
;
4021 frame
->buffer
= (guint8
*) g_malloc (frame
->buflen
);
4022 memcpy (frame
->buffer
, logo
, frame
->buflen
);
4023 frame
->AddState (MediaFrameDecoded
);
4025 //printf ("NullVideoDecoder::DecodeFrame () pts: %" G_GUINT64_FORMAT ", w: %i, h: %i\n", frame->pts, w, h);
4027 return MEDIA_SUCCESS
;
4031 NullDecoder::DecodeAudioFrame (MediaFrame
*frame
)
4033 AudioStream
*as
= (AudioStream
*) GetStream ();
4038 // discard encoded data
4039 g_free (frame
->buffer
);
4041 // We have no idea here how long the encoded audio data is
4042 // for the first frame we use 0.1 seconds, for the rest
4043 // we calculate the time since the last frame
4045 if (prev_pts
== G_MAXUINT64
|| frame
->pts
<= prev_pts
) {
4046 samples
= as
->GetSampleRate () / 10; // start off sending 0.1 seconds of audio
4048 diff_pts
= frame
->pts
- prev_pts
;
4049 samples
= (float) as
->GetSampleRate () / (TIMESPANTICKS_IN_SECOND_FLOAT
/ (float) diff_pts
);
4051 prev_pts
= frame
->pts
;
4053 data_size
= samples
* as
->GetChannels () * 2 /* 16 bit audio */;
4055 frame
->buflen
= data_size
;
4056 frame
->buffer
= (guint8
*) g_malloc0 (frame
->buflen
);
4058 frame
->AddState (MediaFrameDecoded
);
4060 return MEDIA_SUCCESS
;
4064 NullDecoder::DecodeFrameAsyncInternal (MediaFrame
*frame
)
4066 MediaResult result
= MEDIA_FAIL
;
4067 IMediaStream
*stream
= GetStream ();
4069 if (stream
->GetType () == MediaTypeAudio
) {
4070 result
= DecodeAudioFrame (frame
);
4071 } else if (stream
->GetType () == MediaTypeVideo
) {
4072 result
= DecodeVideoFrame (frame
);
4075 if (MEDIA_SUCCEEDED (result
)) {
4076 ReportDecodeFrameCompleted (frame
);
4078 ReportErrorOccurred (result
);
4083 NullDecoder::OpenDecoderAsyncInternal ()
4086 IMediaStream
*stream
= GetStream ();
4088 if (stream
->GetType () == MediaTypeAudio
)
4089 result
= OpenAudio ();
4090 else if (stream
->GetType () == MediaTypeVideo
)
4091 result
= OpenVideo ();
4093 result
= MEDIA_FAIL
;
4095 if (MEDIA_SUCCEEDED (result
)) {
4096 ReportOpenDecoderCompleted ();
4098 ReportErrorOccurred (result
);
4103 NullDecoder::OpenAudio ()
4105 return MEDIA_SUCCESS
;
4109 NullDecoder::OpenVideo ()
4111 VideoStream
*vs
= (VideoStream
*) GetStream ();
4112 guint32 dest_height
= vs
->height
;
4113 guint32 dest_width
= vs
->width
;
4116 // We assume that the input image is a 24 bit bitmap (bmp), stored bottum up and flipped vertically.
4117 extern const char moonlight_logo
[];
4118 const char *image
= moonlight_logo
;
4120 guint32 img_offset
= *((guint32
*)(image
+ 10));
4121 guint32 img_width
= *((guint32
*)(image
+ 18));
4122 guint32 img_height
= *((guint32
*)(image
+ 22));
4123 guint32 img_stride
= (img_width
* 3 + 3) & ~3; // in bytes
4124 guint32 img_i
, img_h
, img_w
;
4125 guint32 start_w
= (dest_width
-img_width
)/2;
4126 guint32 end_w
= start_w
+ img_width
;
4127 guint32 start_h
= (dest_height
-img_height
)/2;
4128 guint32 end_h
= start_h
+ img_height
;
4130 LOG_PIPELINE ("offset: %i, width: 0x%x = %i, height: 0x%x = %i, stride: %i\n", img_offset
, img_width
, img_width
, img_height
, img_height
, img_stride
);
4132 // create the buffer for our image
4133 logo_size
= dest_height
* dest_width
* 4;
4134 logo
= (guint8
*) g_malloc (logo_size
);
4135 memset (logo
, 0x00, logo_size
);
4137 // write our image centered into the destination rectangle, flipped horizontally
4139 for (guint32 dest_h
= 0; dest_h
< dest_height
; dest_h
++) {
4140 for (guint32 dest_w
= 0; dest_w
< dest_width
; dest_w
++) {
4141 if (dest_w
>= start_w
&& dest_w
< end_w
&& dest_h
>= start_h
&& dest_h
< end_h
) {
4142 img_h
= (dest_h
- start_h
) % img_height
;
4143 img_w
= (dest_w
- start_w
) % img_width
;
4144 img_i
= img_h
* img_stride
+ img_w
* 3;
4146 logo
[logo_size
- dest_i
+ 0] = image
[img_offset
+ img_i
+ 0];
4147 logo
[logo_size
- dest_i
+ 1] = image
[img_offset
+ img_i
+ 1];
4148 logo
[logo_size
- dest_i
+ 2] = image
[img_offset
+ img_i
+ 2];
4150 logo
[logo_size
- dest_i
+ 3] = 0xff;
4156 // Flip the image vertically
4157 for (guint32 dest_h
= 0; dest_h
< dest_height
; dest_h
++) {
4158 for (guint32 dest_w
= 0; dest_w
< dest_width
/ 2; dest_w
++) {
4160 guint32 a
= (dest_h
* dest_width
+ dest_w
) * 4;
4161 guint32 b
= (dest_h
* dest_width
+ dest_width
- dest_w
) * 4 - 4;
4162 for (guint32 c
= 0; c
< 3; c
++) {
4164 logo
[a
+ c
] = logo
[b
+ c
];
4170 SetPixelFormat (MoonPixelFormatRGB32
);
4172 return MEDIA_SUCCESS
;
4179 ExternalDemuxer::ExternalDemuxer (Media
*media
, void *instance
, CloseDemuxerCallback close_demuxer
,
4180 GetDiagnosticAsyncCallback get_diagnostic
, GetFrameAsyncCallback get_sample
, OpenDemuxerAsyncCallback open_demuxer
,
4181 SeekAsyncCallback seek
, SwitchMediaStreamAsyncCallback switch_media_stream
)
4182 : IMediaDemuxer (Type::EXTERNALDEMUXER
, media
)
4184 g_return_if_fail (instance
!= NULL
);
4185 g_return_if_fail (close_demuxer
!= NULL
&& get_diagnostic
!= NULL
&& get_sample
!= NULL
&& open_demuxer
!= NULL
&& seek
!= NULL
&& switch_media_stream
!= NULL
);
4187 this->close_demuxer_callback
= close_demuxer
;
4188 this->get_diagnostic_async_callback
= get_diagnostic
;
4189 this->get_sample_async_callback
= get_sample
;
4190 this->open_demuxer_async_callback
= open_demuxer
;
4191 this->seek_async_callback
= seek
;
4192 this->switch_media_stream_async_callback
= switch_media_stream
;
4193 this->instance
= instance
;
4197 ExternalDemuxer::Dispose ()
4200 close_demuxer_callback
= NULL
;
4201 get_diagnostic_async_callback
= NULL
;
4202 get_sample_async_callback
= NULL
;
4203 open_demuxer_async_callback
= NULL
;
4204 seek_async_callback
= NULL
;
4205 switch_media_stream_async_callback
= NULL
;
4207 IMediaDemuxer::Dispose ();
4211 ExternalDemuxer::SetCanSeek (bool value
)
4213 g_warning ("TODO: ExternalDemuxer::SetCanSeek ()");
4217 ExternalDemuxer::AddStream (IMediaStream
*stream
)
4219 return IMediaDemuxer::AddStream (stream
);
4223 ExternalDemuxer::CloseDemuxerInternal ()
4225 g_return_if_fail (close_demuxer_callback
!= NULL
);
4227 close_demuxer_callback (instance
);
4231 ExternalDemuxer::GetDiagnosticAsyncInternal (MediaStreamSourceDiagnosticKind diagnosticsKind
)
4233 g_return_if_fail (get_diagnostic_async_callback
!= NULL
);
4235 get_diagnostic_async_callback (instance
, diagnosticsKind
);
4239 ExternalDemuxer::GetFrameAsyncInternal (IMediaStream
*stream
)
4241 g_return_if_fail (get_sample_async_callback
!= NULL
);
4242 g_return_if_fail (stream
!= NULL
);
4244 get_sample_async_callback (instance
, stream
->GetStreamType ());
4248 ExternalDemuxer::OpenDemuxerAsyncInternal ()
4250 g_return_if_fail (open_demuxer_async_callback
!= NULL
);
4252 open_demuxer_async_callback (instance
, this);
4256 ExternalDemuxer::SeekAsyncInternal (guint64 seekToTime
)
4258 g_return_if_fail (seek_async_callback
!= NULL
);
4260 seek_async_callback (instance
, seekToTime
);
4264 ExternalDemuxer::SwitchMediaStreamAsyncInternal (IMediaStream
*mediaStreamDescription
)
4266 g_return_if_fail (switch_media_stream_async_callback
!= NULL
);
4267 g_return_if_fail (mediaStreamDescription
!= NULL
);
4269 switch_media_stream_async_callback (instance
, mediaStreamDescription
);
4277 AudioStream::AudioStream (Media
*media
)
4278 : IMediaStream (Type::AUDIOSTREAM
, media
)
4282 AudioStream::AudioStream (Media
*media
, int codec_id
, int bits_per_sample
, int block_align
, int sample_rate
, int channels
, int bit_rate
, gpointer extra_data
, guint32 extra_data_size
)
4283 : IMediaStream (Type::AUDIOSTREAM
, media
)
4285 this->codec_id
= codec_id
;
4286 this->codec
= CreateCodec (codec_id
);
4287 this->extra_data
= extra_data
;
4288 this->extra_data_size
= extra_data_size
;
4289 input_bits_per_sample
= bits_per_sample
;
4290 output_bits_per_sample
= bits_per_sample
;
4291 input_block_align
= block_align
;
4292 output_block_align
= block_align
;
4293 input_sample_rate
= sample_rate
;
4294 output_sample_rate
= sample_rate
;
4295 input_channels
= channels
;
4296 output_channels
= channels
;
4297 input_bit_rate
= bit_rate
;
4298 output_bit_rate
= bit_rate
;
4305 ExternalDecoder::ExternalDecoder (Media
*media
, IMediaStream
*stream
, void *instance
, const char *name
,
4306 ExternalDecoder_DecodeFrameAsyncCallback decode_frame_async
,
4307 ExternalDecoder_OpenDecoderAsyncCallback open_decoder_async
,
4308 ExternalDecoder_CleanupCallback cleanup
,
4309 ExternalDecoder_CleanStateCallback clean_state
,
4310 ExternalDecoder_HasDelayedFrameCallback has_delayed_frame
,
4311 ExternalDecoder_DisposeCallback dispose
,
4312 ExternalDecoder_DtorCallback dtor
)
4313 : IMediaDecoder (Type::EXTERNALDECODER
, media
, stream
)
4315 this->instance
= instance
;
4316 this->name
= g_strdup (name
);
4317 this->decode_frame_async
= decode_frame_async
;
4318 this->open_decoder_async
= open_decoder_async
;
4319 this->cleanup
= cleanup
;
4320 this->clean_state
= clean_state
;
4321 this->has_delayed_frame
= has_delayed_frame
;
4322 this->dispose
= dispose
;
4326 ExternalDecoder::~ExternalDecoder ()
4333 ExternalDecoder::DecodeFrameAsyncInternal (MediaFrame
*frame
)
4335 decode_frame_async (instance
, frame
);
4339 ExternalDecoder::OpenDecoderAsyncInternal ()
4341 open_decoder_async (instance
);
4345 ExternalDecoder::Dispose ()
4349 IMediaDecoder::Dispose ();
4353 ExternalDecoder::Cleanup (MediaFrame
*frame
)
4355 cleanup (instance
, frame
);
4359 ExternalDecoder::CleanState ()
4361 clean_state (instance
);
4365 ExternalDecoder::HasDelayedFrame ()
4367 return has_delayed_frame (instance
);
4371 ExternalDecoder::InputEnded ()
4373 GetStream ()->SetOutputEnded (true);
4377 * ExternalDecoderInfo
4380 ExternalDecoderInfo::ExternalDecoderInfo (void *instance
, const char *name
, ExternalDecoderInfo_SupportsCallback supports
, ExternalDecoderInfo_Create create
, ExternalDecoderInfo_dtor dtor
)
4382 this->instance
= instance
;
4383 this->supports
= supports
;
4384 this->create
= create
;
4386 this->name
= g_strdup (name
);
4390 ExternalDecoderInfo::Supports (const char *codec
)
4392 return supports (instance
, codec
);
4396 ExternalDecoderInfo::Create (Media
*media
, IMediaStream
*stream
)
4398 return create (instance
, media
, stream
);
4401 ExternalDecoderInfo::~ExternalDecoderInfo ()