2009-09-12 Chris Toshok <toshok@ximian.com>
[moon.git] / src / pipeline.cpp
blob3ed85605ef4e7ad25506d391d7df6ae1693a857f
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * pipeline.cpp: Pipeline for the media
5 * Contact:
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.
15 #include <config.h>
16 #include <stdio.h>
17 #include <sys/types.h>
18 #include <unistd.h>
19 #include <fcntl.h>
20 #include <errno.h>
21 #include <stdlib.h>
23 #include <pthread.h>
24 #include <sched.h>
26 #include <dlfcn.h>
28 #include "audio.h"
29 #include "pipeline.h"
30 #include "codec-version.h"
31 #include "pipeline-ffmpeg.h"
32 #include "mp3.h"
33 #include "uri.h"
34 #include "media.h"
35 #include "mediaelement.h"
36 #include "asf/asf.h"
37 #include "asf/asf-structures.h"
38 #include "yuv-converter.h"
39 #include "runtime.h"
40 #include "mms-downloader.h"
41 #include "pipeline-ui.h"
42 #include "pipeline-asf.h"
43 #include "playlist.h"
44 #include "deployment.h"
47 * Media
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 ();
67 playlist = root;
68 buffering_time = 0;
69 file = NULL;
70 uri = NULL;
71 source = NULL;
72 demuxer = NULL;
73 markers = NULL;
75 initialized = false;
76 opened = false;
77 opening = false;
78 stopping = false;
79 stopped = false;
80 error_reported = false;
81 buffering_enabled = false;
82 in_open_internal = false;
83 http_retried = 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);
99 Media::~Media ()
101 LOG_PIPELINE ("Media::~Media (), id: %i\n", GET_OBJ_ID (this));
102 pthread_mutex_destroy (&queue_mutex);
103 pthread_cond_destroy (&queue_condition);
106 void
107 Media::ShuttingDownHandler (Deployment *obj, EventArgs *args)
109 VERIFY_MAIN_THREAD;
110 StopThread ();
113 void
114 Media::Dispose ()
116 IMediaSource *src;
117 IMediaDemuxer *dmx;
119 LOG_PIPELINE ("Media::Dispose (), id: %i\n", GET_OBJ_ID (this));
121 ClearQueue (true);
123 if (!stopped && !InMediaThread ())
124 pthread_join (queue_thread, NULL);
126 g_free (file);
127 file = NULL;
128 g_free (uri);
129 uri = NULL;
131 src = this->source;
132 this->source = NULL;
133 if (src) {
134 src->Dispose ();
135 src->unref ();
138 dmx = this->demuxer;
139 this->demuxer = NULL;
140 if (dmx) {
141 dmx->Dispose ();
142 dmx->unref ();
145 delete markers;
146 markers = NULL;
148 if (Surface::InMainThread ()) {
149 RemoveShuttingDownHandler (this);
150 } else {
151 AddTickCallSafe (RemoveShuttingDownHandler);
154 IMediaObject::Dispose ();
157 void
158 Media::RemoveShuttingDownHandler (EventObject *obj)
160 VERIFY_MAIN_THREAD;
161 // event handling must be done on the main thread
162 obj->GetDeployment ()->RemoveHandler (Deployment::ShuttingDownEvent, ShuttingDownCallback, obj);
165 bool
166 Media::IsMSCodecsInstalled ()
168 return registered_ms_codecs;
171 void
172 Media::RegisterMSCodecs (void)
174 register_codec reg;
175 void *dl;
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");
183 return;
186 if (home != NULL)
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);
196 if (dl != NULL) {
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]);
201 if (reg != NULL) {
202 (*reg) (MOONLIGHT_CODEC_ABI_VERSION);
203 } else {
204 LOG_CODECS ("Moonlight: Cannot find %s in %s.\n", functions [i], libmscodecs_path);
207 registered_ms_codecs = true;
208 } else {
209 LOG_CODECS ("Moonlight: Cannot load %s: %s\n", libmscodecs_path, dlerror ());
211 g_free (libmscodecs_path);
213 registering_ms_codecs = false;
216 void
217 Media::SetBufferingEnabled (bool value)
219 buffering_enabled = value;
220 WakeUp ();
223 void
224 Media::SetBufferingTime (guint64 buffering_time)
226 pthread_mutex_lock (&queue_mutex);
227 this->buffering_time = buffering_time;
228 pthread_mutex_unlock (&queue_mutex);
230 if (demuxer != NULL)
231 demuxer->FillBuffers ();
234 guint64
235 Media::GetBufferingTime ()
237 guint64 result;
238 pthread_mutex_lock (&queue_mutex);
239 result = buffering_time;
240 pthread_mutex_unlock (&queue_mutex);
241 return result;
244 PlaylistRoot *
245 Media::GetPlaylistRoot ()
247 return playlist;
250 List *
251 Media::GetMarkers ()
253 if (markers == NULL)
254 markers = new List ();
256 return markers;
259 void
260 Media::RegisterDemuxer (DemuxerInfo *info)
262 //printf ("Media::RegisterDemuxer (%p - %s)\n", info, info->GetName ());
263 info->next = NULL;
264 if (registered_demuxers == NULL) {
265 registered_demuxers = info;
266 } else {
267 MediaInfo* current = registered_demuxers;
268 while (current->next != NULL)
269 current = current->next;
270 current->next = info;
274 void
275 Media::RegisterConverter (ConverterInfo *info)
277 //printf ("Media::RegisterConverter (%p)\n", info);
278 info->next = NULL;
279 if (registered_converters == NULL) {
280 registered_converters = info;
281 } else {
282 MediaInfo *current = registered_converters;
283 while (current->next != NULL)
284 current = current->next;
285 current->next = info;
289 void
290 Media::RegisterDecoder (DecoderInfo *info)
292 MediaInfo *current;
294 //printf ("Media::RegisterDecoder (%p)\n", info);
295 info->next = NULL;
296 if (registered_decoders == NULL) {
297 registered_decoders = info;
298 } else {
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;
306 } else {
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 ());
316 void
317 Media::Initialize ()
319 LOG_PIPELINE ("Media::Initialize ()\n");
321 // demuxers
322 Media::RegisterDemuxer (new ASFDemuxerInfo ());
323 Media::RegisterDemuxer (new Mp3DemuxerInfo ());
324 Media::RegisterDemuxer (new ASXDemuxerInfo ());
326 // converters
327 if (!(moonlight_flags & RUNTIME_INIT_FFMPEG_YUV_CONVERTER))
328 Media::RegisterConverter (new YUVConverterInfo ());
330 // decoders
331 Media::RegisterDecoder (new ASFMarkerDecoderInfo ());
332 if (moonlight_flags & RUNTIME_INIT_ENABLE_MS_CODECS) {
333 RegisterMSCodecs ();
335 #ifdef INCLUDE_FFMPEG
336 if (!(moonlight_flags & RUNTIME_INIT_DISABLE_FFMPEG_CODECS)) {
337 register_ffmpeg ();
339 #endif
341 Media::RegisterDecoder (new PassThroughDecoderInfo ());
342 Media::RegisterDecoder (new NullDecoderInfo ());
345 void
346 Media::Shutdown ()
348 LOG_PIPELINE ("Media::Shutdown ()\n");
350 MediaInfo *current;
351 MediaInfo *next;
353 current = registered_decoders;
354 while (current != NULL) {
355 next = current->next;
356 delete current;
357 current = next;
359 registered_decoders = NULL;
361 current = registered_demuxers;
362 while (current != NULL) {
363 next = current->next;
364 delete current;
365 current = next;
367 registered_demuxers = NULL;
369 current = registered_converters;
370 while (current != NULL) {
371 next = current->next;
372 delete current;
373 current = next;
375 registered_converters = NULL;
377 // Make sure all threads are stopped
378 AudioPlayer::Shutdown ();
380 LOG_PIPELINE ("Media::Shutdown () [Done]\n");
383 void
384 Media::Warning (MediaResult result, const char *format, ...)
386 va_list args;
388 if (MEDIA_SUCCEEDED (result))
389 return;
391 fprintf (stderr, "Moonlight: MediaResult = %d; ", result);
393 va_start (args, format);
394 vfprintf (stderr, format, args);
395 va_end (args);
397 fputc ('\n', stderr);
400 bool
401 Media::InMediaThread ()
403 return pthread_equal (queue_thread, pthread_self ());
406 void
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)
414 return;
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));
422 void
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)
433 return;
435 if (progress > (download_progress + 0.005) || progress == 1.0 || progress == 0.0) {
436 download_progress = progress;
437 EmitSafe (DownloadProgressChangedEvent, new ProgressEventArgs (progress));
441 void
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");
448 return;
451 demuxer->SeekAsync (pts);
454 void
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);
463 void
464 Media::ReportOpenCompleted ()
466 LOG_PIPELINE ("Media::ReportOpenCompleted (), id: %i\n", GET_OBJ_ID (this));
468 EmitSafe (OpenCompletedEvent);
471 void
472 Media::ReportOpenDemuxerCompleted ()
474 LOG_PIPELINE ("Media::ReportOpenDemuxerCompleted (), id: %i\n", GET_OBJ_ID (this));
476 OpenInternal ();
479 void
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);
486 OpenInternal ();
489 void
490 Media::ReportErrorOccurred (ErrorEventArgs *args)
492 LOG_PIPELINE ("Media::ReportErrorOccurred (%p %s)\n", args, args == NULL ? NULL : args->error_message);
494 if (args) {
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);
496 } else {
497 fprintf (stderr, "Moonlight: Unspecified media error.\n");
500 if (!error_reported) {
501 error_reported = true;
502 EmitSafe (MediaErrorEvent, args);
506 void
507 Media::ReportErrorOccurred (const char *message)
509 LOG_PIPELINE ("Media::ReportErrorOccurred (%s)\n", message);
511 ReportErrorOccurred (new ErrorEventArgs (MediaError, 3001, message));
514 void
515 Media::ReportErrorOccurred (MediaResult result)
517 char *msg = g_strdup_printf ("Media error: %i.", result);
518 ReportErrorOccurred (msg);
519 g_free (msg);
522 void
523 Media::PlayAsync ()
525 LOG_PIPELINE ("Media::PlayAsync ()\n");
528 void
529 Media::PauseAsync ()
531 LOG_PIPELINE ("Media::PauseAsync ()\n");
534 void
535 Media::StopAsync ()
537 LOG_PIPELINE ("Media::StopAsync ()\n");
540 void
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);
557 if (file == NULL) {
558 ReportErrorOccurred ("Couldn't get downloaded filename.");
559 return;
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)");
565 return;
568 if (file == NULL) {
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.");
574 return;
577 source = new MmsSource (this, downloader);
578 } else {
579 source = new FileSource (this, file);
582 Initialize (source);
583 source->unref ();
586 void
587 Media::Initialize (IMediaSource *source)
589 MediaResult result;
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);
600 return;
603 initialized = true;
604 this->source = source;
605 this->source->ref ();
608 void
609 Media::Initialize (const char *uri)
611 Downloader *dl;
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);
629 if (dl == NULL) {
630 ReportErrorOccurred ("Couldn't create downloader.");
631 return;
634 dl->Open ("GET", uri, StreamingPolicy);
636 if (dl->GetFailedMessage () == NULL) {
637 Initialize (dl, NULL);
638 } else {
639 ReportErrorOccurred (new ErrorEventArgs (MediaError, 4001, "AG_E_NETWORK_ERROR"));
642 dl->unref ();
644 return;
647 source = new ProgressiveSource (this, uri);
648 Initialize (source);
649 source->unref ();
652 void
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 ();
664 initialized = true;
668 void
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);
678 if (http_retried) {
679 ReportErrorOccurred (args);
680 return;
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);
691 } else {
692 ReportErrorOccurred (args);
693 return;
696 http_retried = true;
698 LOG_PIPELINE ("Media::RetryHttp (), new uri: '%s'\n", http_uri);
700 g_free (uri);
701 uri = NULL;
702 source->Dispose ();
703 source->unref ();
704 source = NULL;
705 initialized = false;
707 Initialize (http_uri);
709 g_free (http_uri);
711 if (!error_reported)
712 OpenAsync ();
715 void
716 Media::OpenAsync ()
718 LOG_PIPELINE ("Media::OpenAsync (), id: %i\n", GET_OBJ_ID (this));
720 g_return_if_fail (initialized == true);
722 EmitSafe (OpeningEvent);
724 OpenInternal ();
727 void
728 Media::OpenInternal ()
730 LOG_PIPELINE ("Media::OpenInternal (), id: %i\n", GET_OBJ_ID (this));
732 g_return_if_fail (initialized == true);
734 if (opened) {
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");
742 return;
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);
751 closure->unref ();
752 return;
755 in_open_internal = true;
757 if (error_reported)
758 goto cleanup;
760 if (!SelectDemuxerAsync ()) {
761 LOG_PIPELINE ("Media::OpenInteral (): no demuxer yet.\n");
762 goto cleanup;
765 if (error_reported)
766 goto cleanup;
768 if (!SelectDecodersAsync ()) {
769 LOG_PIPELINE ("Media::OpenInteral (): no decoders yet.\n");
770 goto cleanup;
773 demuxer->FillBuffers ();
775 opened = true;
776 opening = false;
778 LOG_PIPELINE ("Media::OpenInteral (): opened successfully.\n");
780 EmitSafe (OpenCompletedEvent);
782 cleanup:
783 in_open_internal = false;
786 MediaResult
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;
798 bool
799 Media::SelectDemuxerAsync ()
801 DemuxerInfo *demuxerInfo;
802 MediaResult support;
803 MediaResult result;
804 bool eof;
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 ())
814 return true;
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)) {
828 if (!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);
834 closure->unref ();
836 return false;
840 // Select a demuxer
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)
847 break;
849 result = support;
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);
856 closure->unref ();
858 return 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;
869 if (!source_name) {
870 switch (source->GetType ()) {
871 case MediaSourceTypeProgressive:
872 case MediaSourceTypeFile:
873 source_name = ((FileSource *) source)->GetFileName ();
874 break;
875 case MediaSourceTypeMms:
876 case MediaSourceTypeMmsEntry:
877 source_name = "live source";
878 break;
879 default:
880 source_name = "unknown source";
881 break;
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));
886 g_free (msg);
887 return false;
890 // Found a demuxer
891 demuxer = demuxerInfo->Create (this, source);
892 } else {
893 LOG_PIPELINE ("Media::SelectDemuxer (): The source created the demuxer (%s).\n", demuxer->GetTypeName ());
896 if (demuxer->IsOpened ())
897 return true;
899 if (demuxer->IsOpening ())
900 return false;
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 ();
911 bool
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.");
921 return false;
924 // If the demuxer has no streams (ASXDemuxer for instance)
925 // then just return success.
926 if (demuxer->GetStreamCount () == 0)
927 return true;
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");
938 return false;
941 if (stream->GetDecoder () != NULL)
942 continue;
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);
957 continue;
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);
964 decoder->unref ();
967 if (error_reported)
968 return false;
970 // Open the codecs
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;
977 if (stream == NULL)
978 continue;
980 decoder = stream->GetDecoder ();
982 if (decoder == NULL) {
983 ReportErrorOccurred (new ErrorEventArgs (MediaError, 3001, "AG_E_INVALID_FILE_FORMAT"));
984 return false;
987 if (decoder->IsOpening () || decoder->IsOpened ())
988 continue;
990 decoder->OpenDecoderAsync ();
993 if (error_reported)
994 return false;
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;
1003 if (stream == NULL)
1004 continue;
1006 decoder = stream->GetDecoder ();
1008 if (decoder == NULL) {
1009 ReportErrorOccurred (MEDIA_FAIL);
1010 return false;
1013 if (decoder->IsOpening ()) {
1014 MediaClosure *closure = new MediaClosure (this, OpenInternal, this);
1015 EnqueueWork (closure, false);
1016 closure->unref ();
1017 return 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);
1023 return false;
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;
1037 if (stream == NULL)
1038 continue;
1040 decoder = stream->GetDecoder ();
1042 if (decoder == NULL) {
1043 ReportErrorOccurred (MEDIA_FAIL);
1044 return false;
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);
1068 return false;
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);
1081 return false;
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);
1090 if (stream == NULL)
1091 continue;
1093 if (stream->GetDecoder () != NULL)
1094 return true;
1097 // No codecs found for no stream, report an error.
1098 ReportErrorOccurred ("Didn't find any codecs for any stream.");
1099 return false;
1102 void *
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);
1117 return NULL;
1120 void
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 ();
1147 if (node != NULL)
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);
1155 break;
1158 if (node == NULL)
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);
1168 delete node;
1171 stopped = true;
1173 LOG_PIPELINE ("Media::WorkerLoop (): exiting.\n");
1176 bool
1177 Media::EnqueueWork (MediaClosure *closure, bool wakeup)
1179 bool result;
1180 MediaWork *work;
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);
1192 result = true;
1193 } else {
1194 delete work;
1195 result = false;
1198 if (wakeup)
1199 pthread_cond_signal (&queue_condition);
1201 pthread_mutex_unlock (&queue_mutex);
1203 return result;
1206 MediaResult
1207 Media::DisposeObjectInternal (MediaClosure *closure)
1209 closure->GetContext ()->Dispose ();
1210 return MEDIA_SUCCESS;
1213 void
1214 Media::DisposeObject (EventObject *obj)
1216 MediaDisposeObjectClosure *closure = new MediaDisposeObjectClosure (this, DisposeObjectInternal, obj);
1217 if (!EnqueueWork (closure, true)) {
1218 #if DEBUG && SANITY
1219 printf ("Media::DisposeObject (%p): Could not add callback to the media thread, calling Dispose directly.\n", obj);
1220 #endif
1221 obj->Dispose ();
1223 closure->unref ();
1226 void
1227 Media::WakeUp ()
1229 pthread_mutex_lock (&queue_mutex);
1230 pthread_cond_signal (&queue_condition);
1231 pthread_mutex_unlock (&queue_mutex);
1234 void
1235 Media::ClearQueue ()
1237 ClearQueue (false);
1240 void
1241 Media::ClearQueue (bool delete_queue)
1243 LOG_PIPELINE ("Media::ClearQueue ().\n");
1244 if (queued_requests != NULL) {
1245 List::Node *next;
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);
1252 if (delete_queue) {
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;
1269 delete current;
1270 current = next;
1275 void
1276 Media::StopThread ()
1278 LOG_PIPELINE ("Media::StopThread ().\n");
1280 if (stopped)
1281 return;
1283 stopping = true;
1284 ClearQueue (true);
1286 pthread_join (queue_thread, NULL);
1288 LOG_PIPELINE ("Media::StopThread () [Done]\n");
1292 * ASXDemuxer
1295 ASXDemuxer::ASXDemuxer (Media *media, IMediaSource *source)
1296 : IMediaDemuxer (Type::ASXDEMUXER, media, source)
1298 playlist = NULL;
1301 ASXDemuxer::~ASXDemuxer ()
1305 void
1306 ASXDemuxer::Dispose ()
1308 if (playlist) {
1309 playlist->unref ();
1310 playlist = NULL;
1312 IMediaDemuxer::Dispose ();
1315 void
1316 ASXDemuxer::OpenDemuxerAsyncInternal ()
1318 MediaResult result;
1319 PlaylistRoot *root;
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 ();
1334 playlist->ref ();
1335 } else {
1336 result = MEDIA_FAIL;
1337 args = parser->GetErrorEventArgs ();
1338 if (args != NULL)
1339 args->ref ();
1342 delete parser;
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);
1349 } else {
1350 ReportErrorOccurred (result);
1352 if (args)
1353 args->unref ();
1355 media->unref ();
1359 * ASXDemuxerInfo
1362 MediaResult
1363 ASXDemuxerInfo::Supports (IMediaSource *source)
1365 if (PlaylistParser::IsASX2 (source) || PlaylistParser::IsASX3 (source)) {
1366 return MEDIA_SUCCESS;
1367 } else {
1368 return MEDIA_FAIL;
1372 IMediaDemuxer *
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;
1392 gint32
1393 ManagedStreamSource::ReadInternal (void *buf, guint32 n)
1395 return stream.Read (stream.handle, buf, 0, n);
1398 gint32
1399 ManagedStreamSource::PeekInternal (void *buf, guint32 n)
1401 int read;
1403 read = stream.Read (stream.handle, buf, 0, n);
1404 stream.Seek (stream.handle, -read, 1 /* SeekOrigin.Current */);
1405 return read;
1408 bool
1409 ManagedStreamSource::SeekInternal (gint64 offset, int mode)
1411 stream.Seek (stream.handle, offset, mode /* FIXME: check if mode values matches SeekOrigin values */);
1412 return true;
1415 gint64
1416 ManagedStreamSource::GetPositionInternal ()
1418 return stream.Position (stream.handle);
1421 gint64
1422 ManagedStreamSource::GetSizeInternal ()
1424 return stream.Length (stream.handle);
1428 * FileSource
1431 FileSource::FileSource (Media *media, const char *filename) : IMediaSource (Type::FILESOURCE, media)
1433 this->filename = g_strdup (filename);
1434 fd = NULL;
1435 size = 0;
1436 temp_file = false;
1439 FileSource::FileSource (Media *media, bool temp_file) : IMediaSource (Type::FILESOURCE, media)
1441 filename = NULL;
1442 fd = NULL;
1443 size = 0;
1444 this->temp_file = temp_file;
1447 FileSource::~FileSource ()
1451 void
1452 FileSource::Dispose ()
1454 g_free (filename);
1455 filename = NULL;
1456 if (fd != NULL) {
1457 fclose (fd);
1458 fd = NULL;
1460 IMediaSource::Dispose ();
1463 MediaResult
1464 FileSource::Initialize ()
1466 int tmp_fd;
1468 LOG_PIPELINE ("FileSource::Initialize ()\n");
1470 if (fd != NULL)
1471 return MEDIA_SUCCESS;
1473 if (temp_file) {
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) {
1480 g_free (filename);
1481 filename = NULL;
1483 return MEDIA_FAIL;
1486 fd = fdopen (tmp_fd, "r");
1488 setvbuf (fd, buffer, _IOFBF, sizeof (buffer));
1489 } else {
1490 if (filename == NULL)
1491 return MEDIA_FILE_ERROR;
1493 fd = fopen (filename, "r");
1496 if (fd == NULL)
1497 return MEDIA_FILE_ERROR;
1499 UpdateSize ();
1501 return MEDIA_SUCCESS;
1504 MediaResult
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);
1512 if (fd != NULL) {
1513 fclose (fd);
1514 fd = NULL;
1517 fd = fopen (filename, "r");
1519 if (fd == NULL)
1520 return MEDIA_FAIL;
1522 UpdateSize ();
1524 return MEDIA_SUCCESS;
1527 void
1528 FileSource::UpdateSize ()
1530 struct stat st;
1532 g_return_if_fail (fd != NULL);
1534 if (fstat (fileno (fd), &st) != -1) {
1535 size = st.st_size;
1536 } else {
1537 size = 0;
1541 gint64
1542 FileSource::GetSizeInternal ()
1544 return size;
1547 gint64
1548 FileSource::GetPositionInternal ()
1550 gint64 result;
1552 if (fd == NULL)
1553 return -1;
1555 result = ftell (fd);
1557 LOG_PIPELINE_EX ("FileSource::GetPositionInternal (): result: %lld\n", result);
1559 return result;
1562 bool
1563 FileSource::SeekInternal (gint64 offset, int mode)
1565 gint64 n;
1567 if (fd == NULL)
1568 return false;
1570 LOG_PIPELINE ("FileSource::SeekInternal (%lld, %i)\n", offset, mode);
1572 clearerr (fd);
1573 n = fseek (fd, offset, mode);
1575 return n != -1;
1578 gint32
1579 FileSource::ReadInternal (void *buf, guint32 n)
1581 ssize_t nread = 0;
1583 if (fd == NULL) {
1584 errno = EINVAL;
1585 LOG_PIPELINE_ERROR ("FileSource::ReadInternal (%p, %u): File not open.\n", buf, n);
1586 return -1;
1589 clearerr (fd);
1590 nread = fread (buf, 1, n, fd);
1592 LOG_PIPELINE_EX ("FileSource::ReadInternal (0x????????, %i), nread: %i\n", (int) n, (int) nread);
1594 return nread;
1597 gint32
1598 FileSource::PeekInternal (void *buf, guint32 n)
1600 gint32 result;
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 ());
1608 return result;
1611 bool
1612 FileSource::Eof ()
1614 if (fd == NULL)
1615 return false;
1617 return feof (fd);
1621 * ProgressiveSource
1624 ProgressiveSource::ProgressiveSource (Media *media, const char *uri) : FileSource (media, true)
1626 write_pos = 0;
1627 size = -1;
1628 write_fd = NULL;
1629 cancellable = NULL;
1630 this->uri = g_strdup (uri);
1633 void
1634 ProgressiveSource::Dispose ()
1636 g_free (uri);
1637 uri = NULL;
1639 if (cancellable) {
1640 cancellable->Cancel ();
1641 delete cancellable;
1642 cancellable = NULL;
1645 CloseWriteFile ();
1647 FileSource::Dispose ();
1650 MediaResult
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))
1665 return 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);
1671 g_free (msg);
1672 return MEDIA_FAIL;
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);
1678 } else {
1679 unlink (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);
1686 } else {
1687 result = MEDIA_FAIL;
1688 char *msg = g_strdup_printf ("Could not parse the uri '%s'", uri);
1689 ReportErrorOccurred (msg);
1690 g_free (msg);
1692 delete u;
1694 return result;
1697 void
1698 ProgressiveSource::notify_func (NotifyType type, gint64 args, void *closure)
1700 g_return_if_fail (closure != NULL);
1701 ((ProgressiveSource *) closure)->Notify (type, args);
1704 void
1705 ProgressiveSource::Notify (NotifyType type, gint64 args)
1707 LOG_PIPELINE ("ProgressiveSource::Notify (%i = %s, %" G_GINT64_FORMAT ")\n",
1708 type,
1709 type == ::NotifySize ? "NotifySize" :
1710 (type == NotifyCompleted ? "NotifyCompleted" :
1711 (type == NotifyFailed ? "NotifyFailed" :
1712 (type == NotifyStarted ? "NotifyStarted" :
1713 (type == NotifyProgressChanged ? "NotifyProgressChanged" : "unknown")))),
1714 args);
1716 switch (type) {
1717 case ::NotifySize:
1718 NotifySize (args);
1719 break;
1720 case NotifyCompleted:
1721 DownloadComplete ();
1722 break;
1723 case NotifyFailed:
1724 DownloadFailed ();
1725 break;
1726 case NotifyStarted:
1727 case NotifyProgressChanged:
1728 default:
1729 break;
1733 void
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);
1740 void
1741 ProgressiveSource::DataWrite (void *buf, gint32 offset, gint32 n)
1743 size_t nwritten;
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);
1750 if (n == 0) {
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
1755 CloseWriteFile ();
1757 goto cleanup;
1760 nwritten = fwrite (buf, 1, n, write_fd);
1761 fflush (write_fd);
1763 Lock ();
1764 write_pos += nwritten;
1765 Unlock ();
1767 cleanup:
1768 if (media) {
1769 media->WakeUp ();
1770 media->ReportDownloadProgress ((double) (offset + n) / (double) size);
1771 media->unref ();
1775 void
1776 ProgressiveSource::NotifySize (gint64 size)
1778 LOG_PIPELINE ("ProgressiveSource::NotifySize (%lld)\n", size);
1780 Lock ();
1781 this->size = size;
1782 Unlock ();
1785 void
1786 ProgressiveSource::DownloadComplete ()
1788 MediaResult result = MEDIA_SUCCESS;
1789 Media *media = GetMediaReffed ();
1791 LOG_PIPELINE ("ProgressiveSource::DownloadComplete ()\n");
1793 Lock ();
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
1801 CloseWriteFile ();
1803 Unlock ();
1805 if (!MEDIA_SUCCEEDED (result))
1806 ReportErrorOccurred (result);
1808 if (media) {
1809 media->ReportDownloadProgress (1.0);
1810 media->WakeUp ();
1811 media->unref ();
1815 void
1816 ProgressiveSource::DownloadFailed ()
1818 LOG_PIPELINE ("ProgressiveSource::DownloadFailed ().\n");
1820 ReportErrorOccurred (new ErrorEventArgs (MediaError, 4001, "AG_E_NETWORK_ERROR"));
1823 void
1824 ProgressiveSource::CloseWriteFile ()
1826 if (write_fd == NULL)
1827 return;
1829 fclose (write_fd);
1830 write_fd = NULL;
1834 * MemorySource
1837 MemorySource::MemorySource (Media *media, void *memory, gint32 size, gint64 start, bool owner)
1838 : IMediaSource (Type::MEMORYSOURCE, media)
1840 this->memory = memory;
1841 this->size = size;
1842 this->start = start;
1843 this->pos = 0;
1844 this->owner = owner;
1847 MemorySource::~MemorySource ()
1849 if (owner)
1850 g_free (memory);
1853 bool
1854 MemorySource::SeekInternal (gint64 offset, int mode)
1856 gint64 real_offset;
1858 switch (mode) {
1859 case SEEK_SET:
1860 real_offset = offset - start;
1861 if (real_offset < 0 || real_offset >= size)
1862 return false;
1863 pos = real_offset;
1864 return true;
1865 case SEEK_CUR:
1866 if (pos + offset > size || pos + offset < 0)
1867 return false;
1868 pos += offset;
1869 return true;
1870 case SEEK_END:
1871 if (size - offset > size || size - offset < 0)
1872 return false;
1873 pos = size - offset;
1874 return true;
1875 default:
1876 return false;
1878 return true;
1881 gint32
1882 MemorySource::ReadInternal (void *buffer, guint32 n)
1884 guint32 k = MIN (n, size - pos);
1885 memcpy (buffer, ((char*) memory) + pos, k);
1886 pos += k;
1887 return k;
1890 gint32
1891 MemorySource::PeekInternal (void *buffer, guint32 n)
1893 gint64 start = this->start + pos;
1895 if (this->start > start)
1896 return 0;
1898 if ((this->start + size) < (start + n))
1899 return 0;
1901 memcpy (buffer, ((char*) memory) + this->start - start, n);
1902 return n;
1906 * MediaClosure
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;
1919 if (this->context)
1920 this->context->ref ();
1921 this->media = media;
1922 if (this->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;
1936 if (this->context)
1937 this->context->ref ();
1938 this->media = media;
1939 if (this->media)
1940 this->media->ref ();
1943 void
1944 MediaClosure::Dispose ()
1946 if (context) {
1947 context->unref ();
1948 context = NULL;
1951 if (media) {
1952 media->unref ();
1953 media = NULL;
1956 callback = NULL;
1957 finished = NULL;
1959 EventObject::Dispose ();
1962 void
1963 MediaClosure::Call ()
1965 if (callback) {
1966 result = callback (this);
1967 } else {
1968 result = MEDIA_NO_CALLBACK;
1971 if (finished)
1972 finished (this);
1976 * MediaDisposeObjectClosure
1978 MediaDisposeObjectClosure::MediaDisposeObjectClosure (Media *media, MediaCallback *callback, EventObject *context)
1979 : MediaClosure (media, callback, context)
1983 void
1984 MediaDisposeObjectClosure::Dispose ()
1986 if (!CallExecuted ()) {
1987 // we haven't been executed. do it now.
1988 #if SANITY && DEBUG
1989 LOG_PIPELINE ("MediaDisposeObjectClosure::~MediaDisposeObjectClosure (): callback hasn't been executed, we'll do it now.\n");
1990 #endif
1991 Call ();
1994 MediaClosure::Dispose ();
1998 * MediaSeekClosure
2000 MediaSeekClosure::MediaSeekClosure (Media *media, MediaCallback *callback, IMediaDemuxer *context, guint64 pts)
2001 : MediaClosure (media, callback, context)
2003 this->pts = pts;
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);
2015 this->pts = pts;
2018 MediaReportSeekCompletedClosure::~MediaReportSeekCompletedClosure ()
2022 void
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 ());
2051 void
2052 MediaGetFrameClosure::Dispose ()
2054 if (stream) {
2055 // stream->unref ();
2056 stream = NULL;
2059 MediaClosure::Dispose ();
2060 //fprintf (stderr, "MediaGetFrameClosure::Dispose () id: %i\n", GetId ());
2064 * IMediaStream
2067 IMediaStream::IMediaStream (Type::Kind kind, Media *media) : IMediaObject (kind, media)
2069 context = NULL;
2071 extra_data_size = 0;
2072 extra_data = NULL;
2074 duration = 0;
2076 decoder = NULL;
2077 codec_id = 0;
2078 codec = NULL;
2080 min_padding = 0;
2081 index = -1;
2082 selected = false;
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
2092 void
2093 IMediaStream::Dispose ()
2095 if (decoder) {
2096 IMediaDecoder *d = decoder;
2097 decoder = NULL;
2098 d->Dispose ();
2099 d->unref ();
2101 g_free (extra_data);
2102 extra_data = NULL;
2103 g_free (codec);
2104 codec = NULL;
2106 ClearQueue ();
2107 IMediaObject::Dispose ();
2110 char *
2111 IMediaStream::CreateCodec (int codec_id)
2113 switch (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");
2126 default:
2127 g_warning ("IMediaStream::CreateCodec (%i): Not implemented.\n", codec_id);
2129 /* This algorithm needs testing.
2130 char *result;
2131 int size, current;
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);
2142 current = 0;
2143 if (a)
2144 result [current++] = (char) a;
2145 if (b)
2146 result [current++] = (char) b;
2147 if (c)
2148 result [current++] = (char) c;
2149 if (d)
2150 result [current++] = (char) d;
2151 result [current] = 0;
2153 return g_strdup ("<unknown>");
2158 bool
2159 IMediaStream::IsQueueEmpty ()
2161 return queue.IsEmpty ();
2164 const char *
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";
2175 void
2176 IMediaStream::ReportSeekCompleted ()
2178 ClearQueue ();
2179 if (decoder != NULL)
2180 decoder->ReportSeekCompleted ();
2183 IMediaDemuxer *
2184 IMediaStream::GetDemuxer ()
2186 Media *media;
2187 IMediaDemuxer *result;
2189 if (IsDisposed ())
2190 return NULL;
2192 media = GetMediaReffed ();
2194 g_return_val_if_fail (media != NULL, NULL);
2196 result = media->GetDemuxer ();
2198 media->unref ();
2200 return result;
2203 IMediaDecoder *
2204 IMediaStream::GetDecoder ()
2206 return decoder;
2209 void
2210 IMediaStream::SetDecoder (IMediaDecoder *value)
2212 if (decoder)
2213 decoder->unref ();
2214 decoder = value;
2215 if (decoder)
2216 decoder->ref ();
2219 bool
2220 IMediaStream::GetOutputEnded ()
2222 return output_ended;
2225 void
2226 IMediaStream::SetOutputEnded (bool value)
2228 output_ended = value;
2231 bool
2232 IMediaStream::GetInputEnded ()
2234 return input_ended;
2237 void
2238 IMediaStream::SetInputEnded (bool value)
2240 input_ended = value;
2241 if (GetDecoder () != NULL)
2242 GetDecoder ()->ReportInputEnded ();
2245 guint64
2246 IMediaStream::GetBufferedSize ()
2248 guint64 result;
2250 queue.Lock ();
2251 if (first_pts == G_MAXUINT64 || last_enqueued_pts == G_MAXUINT64)
2252 result = 0;
2253 else if (last_popped_pts == G_MAXUINT64)
2254 result = last_enqueued_pts - first_pts;
2255 else
2256 result = last_enqueued_pts - last_popped_pts;
2257 queue.Unlock ();
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));
2262 return result;
2266 #if DEBUG
2267 #define TO_MS(x) (MilliSeconds_FromPts (x) == 1844674407370955ULL ? -1 : MilliSeconds_FromPts (x))
2269 void
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 ());
2280 } else {
2281 printf ("(not selected) >");
2284 #endif
2286 void
2287 IMediaStream::EnqueueFrame (MediaFrame *frame)
2289 bool first = false;
2290 Media *media = GetMediaReffed ();
2292 g_return_if_fail (media != NULL);
2293 g_return_if_fail (media->InMediaThread ());
2295 queue.Lock ();
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);
2301 #if 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));
2308 #endif
2310 last_enqueued_pts = frame->pts;
2311 first = queue.LinkedList ()->Length () == 0;
2312 queue.LinkedList ()->Append (new StreamNode (frame));
2313 queue.Unlock ();
2315 SetLastAvailablePts (frame->pts);
2317 if (first)
2318 EmitSafe (FirstFrameEnqueuedEvent);
2320 FrameEnqueued ();
2322 media->unref ();
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);
2329 MediaFrame *
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
2338 queue.Lock ();
2339 node = (StreamNode *) queue.LinkedList ()->First ();
2340 if (node != NULL) {
2341 result = node->GetFrame ();
2342 result->ref ();
2343 queue.LinkedList ()->Remove (node);
2344 last_popped_pts = result->pts;
2346 queue.Unlock ();
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 ();
2358 return result;
2361 void
2362 IMediaStream::ClearQueue ()
2364 LOG_BUFFERING ("IMediaStream::ClearQueue ()\n");
2365 queue.Lock ();
2366 queue.LinkedList ()->Clear (true);
2367 first_pts = G_MAXUINT64;
2368 last_popped_pts = G_MAXUINT64;
2369 last_enqueued_pts = G_MAXUINT64;
2370 queue.Unlock ();
2373 void
2374 IMediaStream::SetSelected (bool value)
2376 Media *media = GetMediaReffed ();
2378 selected = value;
2379 if (media) {
2380 if (media->GetDemuxer ())
2381 media->GetDemuxer ()->UpdateSelected (this);
2382 media->unref ();
2387 * IMediaStream.StreamNode
2390 IMediaStream::StreamNode::StreamNode (MediaFrame *f)
2392 frame = f;
2393 frame->ref ();
2396 IMediaStream::StreamNode::~StreamNode ()
2398 frame->unref ();
2399 frame = NULL;
2402 * IMediaDemuxer
2405 IMediaDemuxer::IMediaDemuxer (Type::Kind kind, Media *media, IMediaSource *source) : IMediaObject (kind, media)
2407 this->source = source;
2408 this->source->ref ();
2409 stream_count = 0;
2410 streams = NULL;
2411 opened = false;
2412 opening = false;
2413 pending_stream = NULL;
2416 IMediaDemuxer::IMediaDemuxer (Type::Kind kind, Media *media)
2417 : IMediaObject (kind, media)
2419 source = NULL;
2420 stream_count = 0;
2421 streams = NULL;
2422 opened = false;
2423 opening = false;
2424 pending_stream = NULL;
2427 void
2428 IMediaDemuxer::Dispose ()
2430 if (streams != NULL) {
2431 IMediaStream **tmp = streams;
2432 int stream_count = this->stream_count;
2433 streams = NULL;
2434 for (int i = 0; i < stream_count; i++) {
2435 tmp [i]->Dispose ();
2436 tmp [i]->unref ();
2438 g_free (tmp);
2440 if (source) {
2441 source->unref ();
2442 source = NULL;
2444 if (pending_stream != NULL) {
2445 pending_stream->unref ();
2446 pending_stream = NULL;
2448 opened = false;
2449 IMediaObject::Dispose ();
2452 MediaResult
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;
2465 void
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);
2475 closure->unref ();
2476 media->unref ();
2479 void
2480 IMediaDemuxer::ReportOpenDemuxerCompleted ()
2482 Media *media = GetMediaReffed ();
2484 LOG_PIPELINE ("IMediaDemuxer::ReportDemuxerOpenCompleted () media: %p\n", media);
2486 opened = true;
2487 opening = false;
2489 // Media might be null if we got disposed for some reason.
2490 if (!media)
2491 return;
2493 media->ReportOpenDemuxerCompleted ();
2494 media->unref ();
2497 void
2498 IMediaDemuxer::ReportGetFrameProgress (double progress)
2500 LOG_PIPELINE ("IMediaDemuxer::ReportGetFrameProgress (%f)\n", progress);
2503 void
2504 IMediaDemuxer::ReportSwitchMediaStreamCompleted (IMediaStream *stream)
2506 LOG_PIPELINE ("IMediaDemuxer::ReportSwitchMediaStreamCompleted (%p)\n", stream);
2509 void
2510 IMediaDemuxer::ReportGetDiagnosticCompleted (MediaStreamSourceDiagnosticKind kind, gint64 value)
2512 LOG_PIPELINE ("IMediaDemuxer::ReportGetDiagnosticCompleted (%i, %lld)\n", kind, value);
2515 void
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
2538 FillBuffers ();
2541 MediaResult
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;
2556 void
2557 IMediaDemuxer::EnqueueReportSeekCompleted (guint64 pts)
2559 Media *media = GetMediaReffed ();
2560 MediaClosure *closure = new MediaReportSeekCompletedClosure (media, ReportSeekCompletedCallback, this, pts);
2561 media->EnqueueWork (closure);
2562 closure->unref ();
2563 media->unref ();
2566 void
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);
2577 media->unref ();
2578 return;
2581 for (int i = 0; i < GetStreamCount (); i++) {
2582 IMediaStream *stream = GetStream (i);
2584 if (stream == NULL)
2585 continue;
2587 stream->ReportSeekCompleted ();
2590 media->ReportSeekCompleted (pts);
2591 media->unref ();
2593 FillBuffers ();
2596 void
2597 IMediaDemuxer::OpenDemuxerAsync ()
2599 g_return_if_fail (opened == false);
2601 opening = true;
2602 opened = false;
2603 OpenDemuxerAsyncInternal ();
2606 MediaResult
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;
2622 void
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);
2630 closure->unref ();
2631 media->unref ();
2634 void
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);
2647 return;
2650 pending_stream = stream;
2651 pending_stream->ref ();
2652 GetFrameAsyncInternal (stream);
2653 media->unref ();
2656 MediaResult
2657 IMediaDemuxer::SeekCallback (MediaClosure *closure)
2659 MediaSeekClosure *seek = (MediaSeekClosure *) closure;
2660 seek->GetDemuxer ()->SeekAsync (seek->GetPts ());
2661 return MEDIA_SUCCESS;
2664 void
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);
2674 closure->unref ();
2675 media->unref ();
2678 void
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 ()) {
2688 EnqueueSeek (pts);
2689 } else {
2690 SeekAsyncInternal (pts);
2693 media->unref ();
2696 MediaResult
2697 IMediaDemuxer::FillBuffersCallback (MediaClosure *closure)
2699 IMediaDemuxer *demuxer = (IMediaDemuxer *) closure->GetContext ();
2700 demuxer->FillBuffersInternal ();
2701 return MEDIA_SUCCESS;
2704 void
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);
2714 closure->unref ();
2715 media->unref ();
2718 void
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;
2728 int ended = 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)
2735 return;
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 ())
2748 continue;
2750 if (stream->GetType () != MediaTypeVideo &&
2751 stream->GetType () != MediaTypeAudio)
2752 continue;
2754 media_streams++;
2755 if (stream->GetOutputEnded ()) {
2756 ended++;
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);
2790 } else {
2791 if (min_buffered_size > 0 && buffering_time > 0) {
2792 double progress = ((double) min_buffered_size / (double) buffering_time);
2793 media->ReportBufferingProgress (progress);
2798 media->unref ();
2800 LOG_BUFFERING ("IMediaDemuxer::FillBuffersInternal () [Done]. BufferedSize: %" G_GUINT64_FORMAT " ms\n", MilliSeconds_FromPts (GetBufferedSize ()));
2803 guint64
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 ())
2812 continue;
2814 if (stream->GetType () != MediaTypeVideo && stream->GetType () != MediaTypeAudio)
2815 continue;
2817 result = MIN (result, stream->GetBufferedSize ());
2820 return result;
2823 guint64
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 ())
2833 continue;
2835 result = MIN (result, stream->GetLastAvailablePts ());
2838 if (result == G_MAXUINT64)
2839 result = 0;
2841 return result;
2844 #if DEBUG
2845 void
2846 IMediaDemuxer::PrintBufferInformation ()
2848 printf ("Buffer: %lld", MilliSeconds_FromPts (GetBufferedSize ()));
2849 for (int i = 0; i < GetStreamCount (); i++) {
2850 GetStream (i)->PrintBufferInformation ();
2852 printf ("\n");
2854 #endif
2856 guint64
2857 IMediaDemuxer::GetDuration ()
2859 guint64 result = 0;
2860 for (int i = 0; i < GetStreamCount (); i++)
2861 result = MAX (result, GetStream (i)->duration);
2862 return result;
2865 IMediaStream*
2866 IMediaDemuxer::GetStream (int index)
2868 return (index < 0 || index >= stream_count) ? NULL : streams [index];
2872 * MediaFrame
2875 MediaFrame::MediaFrame (IMediaStream *stream)
2876 : EventObject (Type::MEDIAFRAME)
2878 Initialize ();
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)
2889 Initialize ();
2891 g_return_if_fail (stream != NULL);
2893 this->stream = stream;
2894 this->stream->ref ();
2895 this->buffer = buffer;
2896 this->buflen = buflen;
2897 this->pts = pts;
2899 #if 0
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]);
2904 printf ("\n");
2906 #endif
2908 if (keyframe)
2909 AddState (MediaFrameKeyFrame);
2912 void
2913 MediaFrame::Initialize ()
2915 decoder_specific_data = NULL;
2916 stream = NULL;
2917 marker = NULL;
2919 duration = 0;
2920 pts = 0;
2922 buffer = NULL;
2923 buflen = 0;
2924 state = 0;
2925 event = 0;
2927 for (int i = 0; i < 4; i++) {
2928 data_stride[i] = 0;
2929 srcStride[i] = 0;
2932 srcSlideY = 0;
2933 srcSlideH = 0;
2934 width = 0;
2935 height = 0;
2938 MediaFrame::~MediaFrame ()
2942 void
2943 MediaFrame::Dispose ()
2945 IMediaDecoder *decoder;
2946 Media *media;
2948 #if SANITY
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
2952 // media thread.
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");
2961 media->unref ();
2963 #endif
2965 if (decoder_specific_data != NULL && stream != NULL) {
2966 decoder = stream->GetDecoder ();
2967 if (decoder != NULL)
2968 decoder->Cleanup (this);
2970 g_free (buffer);
2971 buffer = NULL;
2972 if (marker) {
2973 marker->unref ();
2974 marker = NULL;
2976 if (stream) {
2977 stream->unref ();
2978 stream = NULL;
2981 EventObject::Dispose ();
2984 void
2985 MediaFrame::SetSrcSlideY (int value)
2987 srcSlideY = value;
2990 void
2991 MediaFrame::SetSrcSlideH (int value)
2993 srcSlideH = value;
2996 void
2997 MediaFrame::SetSrcStride (int a, int b, int c, int d)
2999 srcStride [0] = a;
3000 srcStride [1] = b;
3001 srcStride [2] = c;
3002 srcStride [3] = d;
3005 void
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 ()
3029 context->unref ();
3030 context = NULL;
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 ();
3043 this->args = args;
3044 if (this->args)
3045 this->args->ref ();
3048 IMediaObject::EmitData::~EmitData ()
3050 context->unref ();
3051 context = NULL;
3052 if (args) {
3053 args->unref ();
3054 args = NULL;
3059 * IMediaObject
3062 IMediaObject::IMediaObject (Type::Kind kind, Media *media)
3063 : EventObject (kind, true)
3065 this->media = media;
3066 if (this->media)
3067 this->media->ref ();
3068 g_return_if_fail (media != NULL);
3069 events = NULL;
3070 emit_on_main_thread = NULL;
3073 void
3074 IMediaObject::Dispose ()
3077 #if SANITY
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
3081 // media thread.
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");
3087 #endif
3089 media_mutex.Lock ();
3090 if (media) {
3091 media->unref ();
3092 media = NULL;
3094 media_mutex.Unlock ();
3096 event_mutex.Lock ();
3097 delete events;
3098 events = NULL;
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 ();
3108 bool
3109 IMediaObject::InMediaThread ()
3111 bool result = true;
3112 #if SANITY
3113 Media *media = GetMediaReffed ();
3114 if (media != NULL) {
3115 result = media->InMediaThread ();
3116 media->unref ();
3118 #endif
3119 return result;
3122 void
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);
3126 EventData *ed;
3128 if (!IsDisposed ()) {
3129 ed = new EventData (event_id, handler, context, invoke_on_main_thread);
3130 event_mutex.Lock ();
3131 if (events == NULL)
3132 events = new List ();
3133 events->Append (ed);
3134 event_mutex.Unlock ();
3138 void
3139 IMediaObject::RemoveSafeHandlers (EventObject *context)
3141 EventData *ed;
3142 EventData *next;
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);
3151 ed = next;
3154 event_mutex.Unlock ();
3157 void
3158 IMediaObject::EmitSafe (int event_id, EventArgs *args)
3160 List *emits = NULL; // The events to emit on this thread.
3161 EventData *ed;
3162 EmitData *emit;
3164 if (events == NULL)
3165 goto cleanup;
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);
3179 } else {
3180 if (emits == NULL)
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
3191 EmitList (emits);
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
3197 List *tmp;
3198 event_mutex.Lock ();
3199 tmp = emit_on_main_thread;
3200 emit_on_main_thread = NULL;
3201 event_mutex.Unlock ();
3202 EmitList (tmp);
3203 } else {
3204 AddTickCallSafe (EmitListCallback);
3207 cleanup:
3208 if (args)
3209 args->unref ();
3212 void
3213 IMediaObject::EmitListMain ()
3215 VERIFY_MAIN_THREAD;
3217 List *list;
3218 event_mutex.Lock ();
3219 list = emit_on_main_thread;
3220 emit_on_main_thread = NULL;
3221 event_mutex.Unlock ();
3222 EmitList (list);
3225 void
3226 IMediaObject::EmitListCallback (EventObject *obj)
3228 IMediaObject *media_obj = (IMediaObject *) obj;
3229 media_obj->EmitListMain ();
3232 void
3233 IMediaObject::EmitList (List *list)
3235 EmitData *emit;
3237 if (list == NULL)
3238 return;
3240 emit = (EmitData *) list->First ();
3241 while (emit != NULL) {
3242 emit->handler (this, emit->args, emit->context);
3243 emit = (EmitData *) emit->next;
3246 delete list;
3249 Media *
3250 IMediaObject::GetMediaReffed ()
3252 Media *result;
3253 media_mutex.Lock ();
3254 result = media;
3255 if (result)
3256 result->ref ();
3257 media_mutex.Unlock ();
3258 return result;
3261 void
3262 IMediaObject::ReportErrorOccurred (char const *message)
3264 g_return_if_fail (media != NULL);
3266 media->ReportErrorOccurred (message);
3269 void
3270 IMediaObject::ReportErrorOccurred (MediaResult result)
3272 g_return_if_fail (media != NULL);
3274 media->ReportErrorOccurred (result);
3277 void
3278 IMediaObject::ReportErrorOccurred (ErrorEventArgs *args)
3280 g_return_if_fail (media != NULL);
3282 media->ReportErrorOccurred (args);
3285 void
3286 IMediaObject::SetMedia (Media *value)
3288 media_mutex.Lock ();
3289 if (media)
3290 media->unref ();
3291 media = value;
3292 if (media)
3293 media->ref ();
3294 media_mutex.Unlock ();
3298 * IMediaSource
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);
3319 void
3320 IMediaSource::Dispose ()
3322 IMediaObject::Dispose ();
3325 void
3326 IMediaSource::Lock ()
3328 pthread_mutex_lock (&mutex);
3331 void
3332 IMediaSource::Unlock ()
3334 pthread_mutex_unlock (&mutex);
3337 gint32
3338 IMediaSource::ReadSome (void *buf, guint32 n)
3340 gint32 result;
3342 LOG_PIPELINE_EX ("IMediaSource<%i>::ReadSome (%p, %u)\n", GET_OBJ_ID (this), buf, n);
3344 Lock ();
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 ());
3350 Unlock ();
3352 return result;
3355 bool
3356 IMediaSource::ReadAll (void *buf, guint32 n)
3358 gint32 read;
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;
3381 bool
3382 IMediaSource::Peek (void *buf, guint32 n)
3384 bool result;
3385 gint64 read;
3387 Lock ();
3389 read = PeekInternal (buf, n);
3390 result = read == (gint64) n;
3392 Unlock ();
3394 LOG_PIPELINE ("IMediaSource::Peek (%p, %u): peek result: %i, read %lld bytes.\n", buf, n, result, read);
3396 return result;
3399 bool
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>")));
3406 bool result;
3407 Lock ();
3408 result = SeekInternal (offset, mode);
3409 Unlock ();
3410 return result;
3413 bool
3414 IMediaSource::IsPositionAvailable (gint64 position, bool *eof)
3416 gint64 available = GetLastAvailablePosition ();
3417 gint64 size = GetSize ();
3419 *eof = false;
3421 if (size != -1 && size < position) {
3422 // Size is known and smaller than the requested position
3423 *eof = true;
3424 return false;
3427 if (available != -1 && available < position) {
3428 // Not everything is available and the available position is smaller than the requested position
3429 *eof = false;
3430 return false;
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
3436 *eof = false;
3437 fprintf (stderr, "Moonlight: media assert error (invalid source size), media playback errors will probably occur\n");
3438 return false;
3441 return true;
3444 gint64
3445 IMediaSource::GetLastAvailablePosition ()
3447 gint64 result;
3448 Lock ();
3449 result = GetLastAvailablePositionInternal ();
3450 Unlock ();
3451 return result;
3454 gint64
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 ();
3461 return -1;
3463 bool
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 ();
3469 return false;
3472 gint32
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 ();
3478 return 0;
3481 gint32
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 ();
3487 return 0;
3490 gint64
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 ();
3496 return 0;
3499 gint64
3500 IMediaSource::GetPosition ()
3502 gint64 result;
3503 Lock ();
3504 result = GetPositionInternal ();
3505 Unlock ();
3506 return result;
3509 gint64
3510 IMediaSource::GetSize ()
3512 gint64 result;
3513 Lock ();
3514 result = GetSizeInternal ();
3515 Unlock ();
3516 return result;
3520 * IMediaDemuxer
3523 void
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 ();
3533 gint32
3534 IMediaDemuxer::AddStream (IMediaStream *stream)
3536 g_return_val_if_fail (stream != NULL, -1);
3538 stream_count++;
3539 streams = (IMediaStream **) g_realloc (streams, stream_count * sizeof (IMediaStream *));
3540 streams [stream_count - 1] = stream;
3541 stream->ref ();
3543 return stream_count - 1;
3547 * IMediaDecoder
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 ();
3559 opening = false;
3560 opened = false;
3561 input_ended = false;
3564 void
3565 IMediaDecoder::Dispose ()
3567 if (stream != NULL) {
3568 IMediaStream *s = stream;
3569 stream = NULL;
3570 s->Dispose ();
3571 s->unref ();
3572 s = NULL;
3575 queue.Clear (true);
3577 IMediaObject::Dispose ();
3580 void
3581 IMediaDecoder::ReportSeekCompleted ()
3583 queue.Clear (true);
3584 input_ended = false;
3585 CleanState ();
3588 void
3589 IMediaDecoder::ReportInputEnded ()
3591 input_ended = true;
3592 if (IsDecoderQueueEmpty ()) {
3593 InputEnded ();
3597 void
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 ())
3609 InputEnded ();
3612 MediaResult
3613 IMediaDecoder::DecodeFrameCallback (MediaClosure *closure)
3616 IMediaDecoder *decoder = (IMediaDecoder *) closure->GetContext ();
3617 IMediaDecoder::FrameNode *node = (IMediaDecoder::FrameNode *) decoder->queue.Pop ();
3619 if (node != NULL) {
3620 decoder->DecodeFrameAsync (node->frame);
3621 delete node;
3624 return MEDIA_SUCCESS;
3627 void
3628 IMediaDecoder::DecodeFrameAsync (MediaFrame *frame)
3630 Media *media;
3632 LOG_PIPELINE ("IMediaDecoder::DecodeFrameAsync (%p) %s\n", frame, (frame && frame->stream) ? frame->stream->GetStreamTypeName () : NULL);
3634 if (IsDisposed ())
3635 return;
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);
3646 closure->unref ();
3647 return;
3650 DecodeFrameAsyncInternal (frame);
3652 media->unref ();
3655 void
3656 IMediaDecoder::OpenDecoderAsync ()
3658 LOG_PIPELINE ("IMediaDecoder::OpenDecoderAsync ()\n");
3660 g_return_if_fail (opening == false);
3661 g_return_if_fail (opened == false);
3663 opening = true;
3664 OpenDecoderAsyncInternal ();
3667 void
3668 IMediaDecoder::ReportOpenDecoderCompleted ()
3670 Media *media = GetMediaReffed ();
3672 LOG_PIPELINE ("IMediaDecoder::ReportOpenDecoderCompleted ()\n");
3674 opening = false;
3675 opened = true;
3677 g_return_if_fail (media != NULL);
3679 media->ReportOpenDecoderCompleted (this);
3680 media->unref ();
3684 * IImageConverter
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;
3695 * VideoStream
3698 VideoStream::VideoStream (Media *media) : IMediaStream (Type::VIDEOSTREAM, media)
3700 converter = NULL;
3701 bits_per_sample = 0;
3702 pts_per_frame = 0;
3703 initial_pts = 0;
3704 height = 0;
3705 width = 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)
3711 converter = NULL;
3712 bits_per_sample = 0;
3713 pts_per_frame = 0;
3714 initial_pts = 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 ()
3728 void
3729 VideoStream::Dispose ()
3731 if (converter) {
3732 converter->Dispose ();
3733 converter->unref ();
3734 converter = NULL;
3736 IMediaStream::Dispose ();
3740 * MediaMarkerFoundClosure
3743 MediaMarkerFoundClosure::MediaMarkerFoundClosure (Media *media, MediaCallback *callback, MediaElement *context)
3744 : MediaClosure (media, callback, context)
3746 marker = NULL;
3749 void
3750 MediaMarkerFoundClosure::Dispose ()
3752 if (marker) {
3753 marker->unref ();
3754 marker = NULL;
3756 MediaClosure::Dispose ();
3759 void
3760 MediaMarkerFoundClosure::SetMarker (MediaMarker *marker)
3762 if (this->marker)
3763 this->marker->unref ();
3764 this->marker = marker;
3765 if (this->marker)
3766 this->marker->ref ();
3770 * MediaMarker
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);
3778 this->pts = pts;
3781 MediaMarker::~MediaMarker ()
3783 g_free (type);
3784 g_free (text);
3788 * MarkerStream
3791 MarkerStream::MarkerStream (Media *media) : IMediaStream (Type::MARKERSTREAM, media)
3793 closure = NULL;
3796 void
3797 MarkerStream::Dispose ()
3799 if (closure) {
3800 closure->unref ();
3801 closure = NULL;
3804 IMediaStream::Dispose ();
3807 void
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");
3814 return;
3817 GetDecoder ()->DecodeFrameAsync (frame);
3820 void
3821 MarkerStream::FrameEnqueued ()
3823 MediaFrame *frame;
3825 LOG_PIPELINE ("MarkerStream::FrameEnqueued ().\n");
3827 frame = PopFrame ();
3829 if (frame == NULL) {
3830 LOG_PIPELINE ("MarkerStream::FrameEnqueued (): No frame.\n");
3831 return;
3834 if (closure != NULL) {
3835 closure->SetMarker (frame->marker);
3836 closure->Call ();
3837 closure->SetMarker (NULL);
3838 } else {
3839 LOG_PIPELINE ("MarkerStream::FrameEnqueued (): No callback.\n");
3840 mutex.Lock ();
3841 list.Append (new MediaMarker::Node (frame->marker));
3842 mutex.Unlock ();
3845 frame->unref ();
3848 MediaMarker *
3849 MarkerStream::Pop ()
3851 MediaMarker *result = NULL;
3852 MediaMarker::Node *node;
3854 mutex.Lock ();
3855 node = (MediaMarker::Node *) list.First ();
3856 if (node != NULL) {
3857 result = node->marker;
3858 result->ref ();
3859 list.Remove (node);
3861 mutex.Unlock ();
3863 return result;
3866 void
3867 MarkerStream::SetCallback (MediaMarkerFoundClosure *closure)
3869 if (this->closure)
3870 this->closure->unref ();
3871 this->closure = closure;
3872 if (this->closure)
3873 this->closure->ref ();
3877 * MediaWork
3879 MediaWork::MediaWork (MediaClosure *c)
3881 g_return_if_fail (c != NULL);
3883 closure = c;
3884 closure->ref ();
3887 MediaWork::~MediaWork ()
3889 g_return_if_fail (closure != NULL);
3891 closure->unref ();
3892 closure = NULL;
3896 * PassThroughDecoderInfo
3899 bool
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]))
3907 return true;
3909 for (int i = 0; audio_fourccs [i] != NULL; i++)
3910 if (!strcmp (codec, audio_fourccs [i]))
3911 return true;
3913 return false;
3917 * PassThroughDecoder
3920 PassThroughDecoder::PassThroughDecoder (Media *media, IMediaStream *stream)
3921 : IMediaDecoder (Type::PASSTHROUGHDECODER, media, stream)
3925 void
3926 PassThroughDecoder::Dispose ()
3928 IMediaDecoder::Dispose ();
3931 void
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
3942 } else {
3943 ReportErrorOccurred (g_strdup_printf ("Unknown fourcc: %s", fourcc));
3944 return;
3947 ReportOpenDecoderCompleted ();
3950 void
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);
3974 * NullDecoderInfo
3977 bool
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]))
3985 return true;
3987 for (int i = 0; audio_fourccs [i] != NULL; i++)
3988 if (!strcmp (codec, audio_fourccs [i]))
3989 return true;
3992 return false;
3996 * NullDecoder
3999 NullDecoder::NullDecoder (Media *media, IMediaStream *stream) : IMediaDecoder (Type::NULLDECODER, media, stream)
4001 logo = NULL;
4002 logo_size = 0;
4003 prev_pts = G_MAXUINT64;
4006 void
4007 NullDecoder::Dispose ()
4009 g_free (logo);
4010 logo = NULL;
4012 IMediaDecoder::Dispose ();
4015 MediaResult
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;
4030 MediaResult
4031 NullDecoder::DecodeAudioFrame (MediaFrame *frame)
4033 AudioStream *as = (AudioStream *) GetStream ();
4034 guint32 samples;
4035 guint32 data_size;
4036 guint64 diff_pts;
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
4047 } else {
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;
4063 void
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);
4077 } else {
4078 ReportErrorOccurred (result);
4082 void
4083 NullDecoder::OpenDecoderAsyncInternal ()
4085 MediaResult result;
4086 IMediaStream *stream = GetStream ();
4088 if (stream->GetType () == MediaTypeAudio)
4089 result = OpenAudio ();
4090 else if (stream->GetType () == MediaTypeVideo)
4091 result = OpenVideo ();
4092 else
4093 result = MEDIA_FAIL;
4095 if (MEDIA_SUCCEEDED (result)) {
4096 ReportOpenDecoderCompleted ();
4097 } else {
4098 ReportErrorOccurred (result);
4102 MediaResult
4103 NullDecoder::OpenAudio ()
4105 return MEDIA_SUCCESS;
4108 MediaResult
4109 NullDecoder::OpenVideo ()
4111 VideoStream *vs = (VideoStream *) GetStream ();
4112 guint32 dest_height = vs->height;
4113 guint32 dest_width = vs->width;
4114 guint32 dest_i = 0;
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
4138 dest_i = 4;
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;
4152 dest_i += 4;
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++) {
4159 guint32 tmp;
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++) {
4163 tmp = logo [a + c];
4164 logo [a + c] = logo [b + c];
4165 logo [b + c] = tmp;
4170 SetPixelFormat (MoonPixelFormatRGB32);
4172 return MEDIA_SUCCESS;
4176 * ExternalDemuxer
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;
4196 void
4197 ExternalDemuxer::Dispose ()
4199 instance = NULL;
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 ();
4210 void
4211 ExternalDemuxer::SetCanSeek (bool value)
4213 g_warning ("TODO: ExternalDemuxer::SetCanSeek ()");
4216 gint32
4217 ExternalDemuxer::AddStream (IMediaStream *stream)
4219 return IMediaDemuxer::AddStream (stream);
4222 void
4223 ExternalDemuxer::CloseDemuxerInternal ()
4225 g_return_if_fail (close_demuxer_callback != NULL);
4227 close_demuxer_callback (instance);
4230 void
4231 ExternalDemuxer::GetDiagnosticAsyncInternal (MediaStreamSourceDiagnosticKind diagnosticsKind)
4233 g_return_if_fail (get_diagnostic_async_callback != NULL);
4235 get_diagnostic_async_callback (instance, diagnosticsKind);
4238 void
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 ());
4247 void
4248 ExternalDemuxer::OpenDemuxerAsyncInternal ()
4250 g_return_if_fail (open_demuxer_async_callback != NULL);
4252 open_demuxer_async_callback (instance, this);
4255 void
4256 ExternalDemuxer::SeekAsyncInternal (guint64 seekToTime)
4258 g_return_if_fail (seek_async_callback != NULL);
4260 seek_async_callback (instance, seekToTime);
4263 void
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);
4274 * AudioStream
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;
4302 * ExternalDecoder
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;
4323 this->dtor = dtor;
4326 ExternalDecoder::~ExternalDecoder ()
4328 dtor (instance);
4329 g_free (name);
4332 void
4333 ExternalDecoder::DecodeFrameAsyncInternal (MediaFrame *frame)
4335 decode_frame_async (instance, frame);
4338 void
4339 ExternalDecoder::OpenDecoderAsyncInternal ()
4341 open_decoder_async (instance);
4344 void
4345 ExternalDecoder::Dispose ()
4347 dispose (instance);
4349 IMediaDecoder::Dispose ();
4352 void
4353 ExternalDecoder::Cleanup (MediaFrame *frame)
4355 cleanup (instance, frame);
4358 void
4359 ExternalDecoder::CleanState ()
4361 clean_state (instance);
4364 bool
4365 ExternalDecoder::HasDelayedFrame ()
4367 return has_delayed_frame (instance);
4370 void
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;
4385 this->dtor = dtor;
4386 this->name = g_strdup (name);
4389 bool
4390 ExternalDecoderInfo::Supports (const char *codec)
4392 return supports (instance, codec);
4395 IMediaDecoder *
4396 ExternalDecoderInfo::Create (Media *media, IMediaStream *stream)
4398 return create (instance, media, stream);
4401 ExternalDecoderInfo::~ExternalDecoderInfo ()
4403 if (dtor != NULL)
4404 dtor (instance);
4405 g_free (name);