2009-10-20 Chris Toshok <toshok@ximian.com>
[moon.git] / src / pipeline.h
blob38ad6d255b04fd259e2b1c3d88f25b0c1f99e612
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * pipeline.h: 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.
14 #ifndef __MOON_PIPELINE_H_
15 #define __MOON_PIPELINE_H_
17 #include <glib.h>
18 #include <stdio.h>
19 #include <pthread.h>
20 #include "utils.h"
21 #include "mutex.h"
23 #define MAKE_CODEC_ID(a, b, c, d) (a | (b << 8) | (c << 16) | (d << 24))
25 #define CODEC_WMV1 MAKE_CODEC_ID ('W', 'M', 'V', '1')
26 #define CODEC_WMV2 MAKE_CODEC_ID ('W', 'M', 'V', '2')
27 #define CODEC_WMV3 MAKE_CODEC_ID ('W', 'M', 'V', '3')
28 #define CODEC_WMVA MAKE_CODEC_ID ('W', 'M', 'V', 'A')
29 #define CODEC_WVC1 MAKE_CODEC_ID ('W', 'V', 'C', '1')
30 #define CODEC_RGBA MAKE_CODEC_ID ('R', 'G', 'B', 'A')
31 #define CODEC_YV12 MAKE_CODEC_ID ('Y', 'V', '1', '2')
32 #define CODEC_MP3 0x55
33 #define CODEC_WMAV1 0x160
34 #define CODEC_WMAV2 0x161
35 #define CODEC_WMAV3 0x162
36 #define CODEC_PCM 0x1
38 #define MAX_VIDEO_HEIGHT 2048
39 #define MAX_VIDEO_WIDTH 2048
41 typedef void (*register_codec) (int abi_version);
44 * Should be capable of:
45 * - play files and live streams
46 * - open a file and get information about its streams
47 * - audio: format, initial_pts, # of channels, sample rate, sample size
48 * - video: format, initial_pts, height, width, frame rate
49 * - needs to be able to pause playback when there's no more source (reached end of downloaded data / progressive downloading)
50 * - informing back about streamed markers (these are quite rare, so it doesn't make sense to poll on every AdvanceFrame if there are any new markers)
55 * Playing media more or less goes like this with async frame reading (from MediaPlayer's perspective)
56 * Open ():
57 * Stop ()
58 * set state to paused
59 * Open the file, read data/headers, initialize whatever has to be initialized
60 * if any video streams, request first frame to be decoded (sync) and show it
61 * Play ():
62 * set state to playing
63 * set flag that we need more frames
64 * enqueue a few frame requests
65 * Pause ():
66 * set state to paused
67 * clear the queue of requested frames (no need to wait until frames being decoded are finished)
68 * Stop ():
69 * set state to stopped
70 * EmptyQueues ()
71 * AdvanceFrame ():
72 * if not playing, return
73 * if no decoded frames, return
74 * aquire queue-lock
75 * pop a decoded video+audio frame
76 * release queue-lock
77 * draw/play a decoded video/audio frame(s)
78 * enqueue more frame requests (one for each drawn/played)
79 * Seek ():
80 * EmptyQueues ()
81 * seek to the desired position
82 * enqueue a few frame requests
83 * EmptyQueues ():
84 * set flag that we need no more frames (saving old state)
85 * clear the queue of requested frames and wait until no more frames are being decoded
86 * // No need to lock here, since we know that nobody will call FrameDecodedCallback now (there are no requested frames)
87 * empty the queue of decoded frames
88 * set flag to saved state
90 * FrameDecodedCallback () -> called on another thread
91 * if flag that we need no more frames is set, do nothing
92 * aquire queue-lock
93 * add the decoded frame to the queue of decoded frames
94 * release queue-lock
100 class Media;
101 class IMediaSource;
102 class IMediaStream;
103 class IMediaDemuxer;
104 class IMediaDecoder;
105 class IMediaObject;
106 class FileSource;
107 class LiveSource;
108 class MediaClosure;
109 class MediaFrame;
110 class VideoStream;
111 class AudioStream;
112 class MarkerStream;
113 class IImageConverter;
114 class MediaMarker;
115 class ProgressiveSource;
116 class MediaMarkerFoundClosure;
117 class Playlist;
119 typedef gint32 MediaResult;
121 #define MEDIA_SUCCESS ((MediaResult) 0)
122 #define MEDIA_FAIL ((MediaResult) 1)
123 #define MEDIA_INVALID_STREAM ((MediaResult) 2)
124 #define MEDIA_UNKNOWN_CODEC ((MediaResult) 3)
125 #define MEDIA_INVALID_MEDIA ((MediaResult) 4)
126 #define MEDIA_FILE_ERROR ((MediaResult) 5)
127 #define MEDIA_CODEC_ERROR ((MediaResult) 6)
128 #define MEDIA_OUT_OF_MEMORY ((MediaResult) 7)
129 #define MEDIA_DEMUXER_ERROR ((MediaResult) 8)
130 #define MEDIA_CONVERTER_ERROR ((MediaResult) 9)
131 #define MEDIA_UNKNOWN_CONVERTER ((MediaResult) 10)
132 #define MEDIA_UNKNOWN_MEDIA_TYPE ((MediaResult) 11)
133 #define MEDIA_CODEC_DELAYED ((MediaResult) 12)
134 #define MEDIA_NO_MORE_DATA ((MediaResult) 13)
135 #define MEDIA_CORRUPTED_MEDIA ((MediaResult) 14)
136 #define MEDIA_NO_CALLBACK ((MediaResult) 15)
137 #define MEDIA_INVALID_DATA ((MediaResult) 16)
138 #define MEDIA_READ_ERROR ((MediaResult) 17)
139 // The pipeline returns this value in GetNextFrame if the
140 // buffer is empty.
141 #define MEDIA_BUFFER_UNDERFLOW ((MediaResult) 18)
142 // This value might be returned by the pipeline for an open
143 // request, indicating that there is not enough data available
144 // to open the media.
145 // It is also used internally in the pipeline whenever something
146 // can't be done because of not enough data.
147 // Note: this value must not be used for eof condition.
148 #define MEDIA_NOT_ENOUGH_DATA ((MediaResult) 19)
149 #define MEDIA_INVALID ((MediaResult) 0xFFFFFFFF)
151 #define MEDIA_SUCCEEDED(x) (((x) <= 0))
153 typedef MediaResult MediaCallback (MediaClosure *closure);
155 #include "list.h"
156 #include "debug.h"
157 #include "dependencyobject.h"
158 #include "error.h"
159 #include "type.h"
160 #include "enums.h"
161 #include "application.h"
164 * MediaClosure:
166 class MediaClosure : public EventObject {
167 private:
168 MediaCallback *callback;
169 MediaResult result;
171 Media *media;
172 EventObject *context; // The property of whoever creates the closure.
173 const char *description;
174 void Init (Media *media, MediaCallback *callback, EventObject *context);
176 protected:
177 virtual ~MediaClosure () {}
178 MediaClosure (Type::Kind object_type, Media *media, MediaCallback *callback, EventObject *context);
180 public:
181 MediaClosure (Media *media, MediaCallback *callback, EventObject *context, const char *description);
182 virtual void Dispose ();
184 void Call (); // Calls the callback and stores the result in 'result', then calls the 'finished' callback
186 bool CallExecuted () { return result != MEDIA_INVALID; }
188 MediaResult GetResult () { return result; }
189 Media *GetMedia () { return media; }
190 EventObject *GetContext () { return context; }
191 const char *GetDescription () { return description != NULL ? description : GetTypeName (); }
195 * MediaDisposeObjectClosure
197 class MediaDisposeObjectClosure : public MediaClosure {
198 public:
199 MediaDisposeObjectClosure (Media *media, MediaCallback *callback, EventObject *context);
200 virtual void Dispose ();
204 * MediaReportSeekCompletedClosure
206 class MediaReportSeekCompletedClosure : public MediaClosure {
207 private:
208 guint64 pts;
210 protected:
211 virtual ~MediaReportSeekCompletedClosure ();
213 public:
214 MediaReportSeekCompletedClosure (Media *media, MediaCallback *callback, IMediaDemuxer *context, guint64 pts);
215 virtual void Dispose ();
217 guint64 GetPts () { return pts; }
218 IMediaDemuxer *GetDemuxer () { return (IMediaDemuxer *) GetContext (); }
222 * MediaGetFrameClosure
224 class MediaGetFrameClosure : public MediaClosure {
225 private:
226 IMediaStream *stream;
228 protected:
229 virtual ~MediaGetFrameClosure ();
231 public:
232 MediaGetFrameClosure (Media *media, MediaCallback *callback, IMediaDemuxer *context, IMediaStream *stream);
233 virtual void Dispose ();
235 IMediaStream *GetStream () { return stream; }
236 IMediaDemuxer *GetDemuxer () { return (IMediaDemuxer *) GetContext (); }
240 * MediaReportFrameCompletedClosure
242 class MediaReportFrameCompletedClosure : public MediaClosure {
243 private:
244 MediaFrame *frame;
246 protected:
247 virtual ~MediaReportFrameCompletedClosure () {}
249 public:
250 MediaReportFrameCompletedClosure (Media *media, MediaCallback *callback, IMediaDemuxer *context, MediaFrame *frame);
251 virtual void Dispose ();
253 MediaFrame *GetFrame () { return frame; }
254 IMediaDemuxer *GetDemuxer () { return (IMediaDemuxer *) GetContext (); }
258 * MediaMarkerFoundClosure
260 class MediaMarkerFoundClosure : public MediaClosure {
261 private:
262 MediaMarker *marker;
264 protected:
265 virtual ~MediaMarkerFoundClosure () {}
267 public:
268 MediaMarkerFoundClosure (Media *media, MediaCallback *callback, MediaElement *context);
269 virtual void Dispose ();
271 MediaMarker *GetMarker () { return marker; }
272 void SetMarker (MediaMarker *marker);
276 * MediaSeekClosure
278 class MediaSeekClosure : public MediaClosure {
279 private:
280 guint64 pts;
282 protected:
283 virtual ~MediaSeekClosure () {}
285 public:
286 MediaSeekClosure (Media *media, MediaCallback *callback, IMediaDemuxer *context, guint64 pts);
288 IMediaDemuxer *GetDemuxer () { return (IMediaDemuxer *) GetContext (); }
289 guint64 GetPts () { return pts; }
293 * *Info classes used to register codecs, demuxers and converters.
296 class MediaInfo {
297 public:
298 MediaInfo *next; // Used internally by Media.
299 MediaInfo () : next (NULL) {}
300 virtual ~MediaInfo () {}
301 virtual const char *GetName () { return "Unknown"; }
304 class DecoderInfo : public MediaInfo {
305 public:
306 virtual bool Supports (const char *codec) = 0;
307 virtual IMediaDecoder *Create (Media *media, IMediaStream *stream) = 0;
309 virtual ~DecoderInfo () {}
312 class DemuxerInfo : public MediaInfo {
313 public:
314 // <buffer> points to the first <length> bytes of a file.
315 // <length> is guaranteed to be at least 16 bytes.
316 // Possible return values:
317 // - MEDIA_SUCCESS: the demuxer supports this source
318 // - MEDIA_FAIL: the demuxer does not support this source
319 // - MEDIA_NOT_ENOUGH_DATA: the source doesn't have enough data available for the demuxer to know if it's a supported format or not.
320 virtual MediaResult Supports (IMediaSource *source) = 0;
321 virtual IMediaDemuxer *Create (Media *media, IMediaSource *source) = 0;
324 class ConverterInfo : public MediaInfo {
325 public:
326 virtual bool Supports (MoonPixelFormat input, MoonPixelFormat output) = 0;
327 virtual IImageConverter *Create (Media *media, VideoStream *stream) = 0;
331 * ProgressEventArgs
333 /* @Namespace=None */
334 class ProgressEventArgs : public EventArgs {
335 public:
336 double progress;
338 ProgressEventArgs (double progress)
340 this->progress = progress;
345 * MediaWork
348 class MediaWork : public List::Node {
349 public:
350 MediaClosure *closure;
351 MediaWork (MediaClosure *closure);
352 virtual ~MediaWork ();
356 * IMediaObject
358 class IMediaObject : public EventObject {
359 private:
360 Media *media;
361 Mutex media_mutex;
362 // Media event handling
363 // media needs to support event handling on all threads, and EventObject isn't thread-safe
364 class EventData : public List::Node {
365 public:
366 int event_id;
367 EventHandler handler;
368 EventObject *context;
369 bool invoke_on_main_thread;
370 EventData (int event_id, EventHandler handler, EventObject *context, bool invoke_on_main_thread);
371 virtual ~EventData ();
373 class EmitData : public List::Node {
374 public:
375 int event_id;
376 EventHandler handler;
377 EventObject *context;
378 EventArgs *args;
379 EmitData (int event_id, EventHandler handler, EventObject *context, EventArgs *args);
380 virtual ~EmitData ();
382 List *events; // list of event handlers
383 List *emit_on_main_thread; // list of emit calls to emit on main thread
384 Mutex event_mutex;
386 void EmitList (List *list);
387 void EmitListMain ();
388 static void EmitListCallback (EventObject *obj);
390 protected:
391 virtual ~IMediaObject () {}
393 public:
394 IMediaObject (Type::Kind kind, Media *media);
395 virtual void Dispose ();
397 /* @GenerateCBinding,GeneratePInvoke */
398 Media *GetMediaReffed ();
399 void SetMedia (Media *value);
401 void ReportErrorOccurred (ErrorEventArgs *args);
402 /* @GenerateCBinding */
403 void ReportErrorOccurred (const char *message);
404 void ReportErrorOccurred (MediaResult result);
406 // All the event methods are thread-safe
407 void AddSafeHandler (int event_id, EventHandler handler, EventObject *context, bool invoke_on_main_thread = true);
408 void RemoveSafeHandlers (EventObject *context);
409 void EmitSafe (int event_id, EventArgs *args = NULL);
412 class IMediaStream : public IMediaObject {
413 private:
414 void *context;
415 bool enabled;
416 bool selected;
417 bool input_ended; // end of stream reached in demuxer
418 bool output_ended; // end of stream reached in decoder
419 guint64 first_pts; // The first pts in the stream, initialized to G_MAXUINT64
420 guint64 last_popped_pts; // The pts of the last frame returned, initialized to G_MAXUINT64
421 guint64 last_enqueued_pts; // The pts of the last frae enqueued, initialized to G_MAXUINT64
422 guint64 last_available_pts; // The last pts available, initialized to 0. Note that this field won't be correct for streams which CanSeekToPts.
423 Queue queue; // Our queue of demuxed frames
424 IMediaDecoder *decoder;
426 protected:
427 virtual ~IMediaStream () {}
428 virtual void FrameEnqueued () {}
430 static char *CreateCodec (int codec_id); // converts fourcc int value into a string
431 public:
432 class StreamNode : public List::Node {
433 private:
434 MediaFrame *frame;
435 public:
436 StreamNode (MediaFrame *frame);
437 virtual ~StreamNode ();
438 MediaFrame *GetFrame () { return frame; }
441 IMediaStream (Type::Kind kind, Media *media);
442 virtual void Dispose ();
444 // Video, Audio, Markers, etc.
445 virtual MediaStreamType GetType () = 0; // TODO: This should be removed, it clashes with GetType in EventObject.
446 /* @GenerateCBinding */
447 virtual MediaStreamType GetStreamType () { return GetType (); }
448 const char *GetStreamTypeName ();
450 IMediaDecoder *GetDecoder ();
451 void SetDecoder (IMediaDecoder *value);
453 // If this stream is enabled (producing output).
454 // A file might have several audio streams,
455 // and live streams might have several video streams with different bitrates.
456 bool IsEnabled () { return enabled; }
457 /* @GenerateCBinding */
458 const char *GetCodec () { return codec; }
460 // User defined context value.
461 void *GetContext () { return context; }
462 void SetContext (void *context) { this->context = context; }
464 bool GetSelected () { return selected; }
465 void SetSelected (bool value);
467 guint32 GetBitrate ();
469 void *extra_data;
470 int extra_data_size;
471 int codec_id;
472 guint64 duration; // 100-nanosecond units (pts)
473 char *codec; // freed upon destruction
474 // The minimum amount of padding any other part of the pipeline needs for frames from this stream.
475 // Used by the demuxer when reading frames, ensures that there are at least min_padding extra bytes
476 // at the end of the frame data (all initialized to 0).
477 int min_padding;
478 // 0-based index of the stream in the media
479 // set by the demuxer, until then its value must be -1
480 int index;
482 void EnqueueFrame (MediaFrame *frame);
483 MediaFrame *PopFrame ();
484 bool IsQueueEmpty ();
485 bool IsInQueue (MediaFrame *frame);
486 void ClearQueue ();
487 guint64 GetFirstPts () { return first_pts; }
488 guint64 GetLastPoppedPts () { return last_popped_pts; }
489 guint64 GetLastEnqueuedPts () { return last_enqueued_pts; }
490 void SetLastAvailablePts (guint64 value) { last_available_pts = MAX (value, last_available_pts); }
491 guint64 GetLastAvailablePts () { return last_available_pts; }
492 guint64 GetBufferedSize (); // Returns the time between the last frame returned and the last frame available (buffer time)
494 /* @GenerateCBinding */
495 int GetExtraDataSize () { return extra_data_size; }
496 /* @GenerateCBinding */
497 void SetExtraDataSize (int value) { extra_data_size = value; }
498 /* @GenerateCBinding */
499 void *GetExtraData () { return extra_data; }
500 /* @GenerateCBinding */
501 void SetExtraData (void *value) { extra_data = value; }
502 /* @GenerateCBinding */
503 int GetCodecId () { return codec_id; }
504 /* @GenerateCBinding */
505 void SetCodecId (int value) { codec_id = value; }
506 /* @GenerateCBinding */
507 guint64 GetDuration () { return duration; }
508 /* @GenerateCBinding */
509 void SetDuration (guint64 value) { duration = value; }
511 bool GetInputEnded ();
512 void SetInputEnded (bool value);
513 bool GetOutputEnded ();
514 void SetOutputEnded (bool value);
516 IMediaDemuxer *GetDemuxer ();
518 void ReportSeekCompleted ();
519 #if DEBUG
520 void PrintBufferInformation ();
521 #endif
522 const static int FirstFrameEnqueuedEvent;
526 * Media
528 class Media : public IMediaObject {
529 private:
530 static ConverterInfo *registered_converters;
531 static DemuxerInfo *registered_demuxers;
532 static DecoderInfo *registered_decoders;
533 static bool registering_ms_codecs;
534 static bool registered_ms_codecs;
536 Mutex mutex;
538 guint64 buffering_time; // Access must be protected with mutex.
539 bool is_disposed; // Access must be protected with mutex. This is used to ensure that we don't add work to the thread pool after having been disposed.
540 char *uri;
541 char *file;
542 IMediaSource *source;
543 IMediaDemuxer *demuxer;
544 List *markers;
545 bool initialized;
546 bool opened;
547 bool opening;
548 bool stopped;
549 bool error_reported; // If an error has been reported.
550 bool buffering_enabled;
551 bool in_open_internal; // detect recursive calls to OpenInternal
552 bool http_retried;
553 double download_progress;
554 double buffering_progress;
556 PlaylistRoot *playlist;
558 // Determines the container type and selects a demuxer. We have support for mp3 and asf demuxers.
559 // Also opens the demuxer.
560 // This method is supposed to be called multiple times, until either 'error_reported' is true or this method
561 // returns true. It will pick up wherever it left working last time.
562 bool SelectDemuxerAsync ();
564 // Selects decoders according to stream info.
565 // - Default is to use any MS decoder if available (and applicable), otherwise ffmpeg.
566 // Overridable by MOONLIGHT_OVERRIDES, set ms-codecs=no to disable ms codecs, and ffmpeg-codecs=no to disable ffempg codecs
567 // This method is supposed to be called multiple times, until either 'error_reported' is true or this method
568 // returns true. It will pick up wherever it left working last time.
569 bool SelectDecodersAsync ();
571 // This method is supposed to be called multiple times, until the media has been successfully opened or an error occurred.
572 void OpenInternal ();
573 static MediaResult OpenInternal (MediaClosure *closure);
574 static MediaResult DisposeObjectInternal (MediaClosure *closure);
576 static MediaResult StopCallback (MediaClosure *closure);
577 static MediaResult PauseCallback (MediaClosure *closure);
578 static MediaResult PlayCallback (MediaClosure *closure);
579 void Stop ();
580 void Pause ();
581 void Play ();
583 protected:
584 virtual ~Media ();
586 public:
587 Media (PlaylistRoot *root);
589 virtual void Dispose ();
591 static bool InMediaThread ();
592 bool EnqueueWork (MediaClosure *closure, bool wakeup = true);
594 // Calls obj->Dispose on the media thread.
595 void DisposeObject (EventObject *obj);
597 // Initialize the Media.
598 // These methods may raise MediaError events.
599 void Initialize (Downloader *downloader, const char *PartName); // MediaElement.SetSource (dl, 'PartName');
600 void Initialize (const char *uri); // MediaElement.Source = 'uri';
601 void Initialize (IMediaDemuxer *demuxer); // MediaElement.SetSource (demuxer);
602 void Initialize (IMediaSource *source);
604 // Start opening the media.
605 // When done, OpenCompleted event is raised.
606 // In case of failure, MediaError event is raised
607 void OpenAsync ();
609 void ReportOpenDemuxerCompleted (); // This method is called by the demuxer when it has opened.
610 void ReportOpenDecoderCompleted (IMediaDecoder *decoder); // This method is called by any of the decoders when it has opened.
611 void ReportOpenCompleted (); // Raise the OpenCompleted event.
613 void ReportDownloadProgress (double progress);
614 void ReportBufferingProgress (double progress);
616 // Media playback
617 void PlayAsync (); // Raises CurrentStateChanged
618 void PauseAsync (); // Raises CurrentStateChanged
619 void StopAsync (); // Raises CurrentStateChanged
620 // Seek to the specified pts
621 // When done, SeekCompleted is raised
622 // In case of failure, MediaError is raised.
623 void SeekAsync (guint64 pts);
624 void ReportSeekCompleted (guint64 pts); // This method is called by IMediaDemuxer when the seek is completed. Raises the SeekCompleted event.
626 void ClearQueue (); // Clears the queue and make sure the thread has finished processing what it's doing
627 void WakeUp ();
629 void SetBufferingTime (guint64 buffering_time);
630 guint64 GetBufferingTime ();
632 void SetBufferingEnabled (bool value);
634 IMediaSource *GetSource () { return source; }
635 IMediaDemuxer *GetDemuxer () { return demuxer; }
636 const char *GetFile () { return file; }
637 const char *GetUri () { return uri; }
638 void SetFileOrUrl (const char *value);
640 static void Warning (MediaResult result, const char *format, ...);
641 // A list of MediaMarker::Node.
642 // This is the list of markers found in the metadata/headers (not as a separate stream).
643 // Will never return NULL.
644 List *GetMarkers ();
645 double GetDownloadProgress () { return download_progress; }
646 double GetBufferingProgress () { return buffering_progress; }
648 PlaylistRoot *GetPlaylistRoot ();
650 bool IsOpened () { return opened; }
651 bool IsOpening () { return opening; }
652 bool IsStopped () { return stopped; }
654 void RetryHttp (ErrorEventArgs *args);
656 void ReportErrorOccurred (ErrorEventArgs *args);
657 void ReportErrorOccurred (const char *message);
658 void ReportErrorOccurred (MediaResult result);
660 bool HasReportedError () { return error_reported; }
662 const static int OpeningEvent;
663 const static int OpenCompletedEvent;
664 const static int SeekingEvent;
665 const static int SeekCompletedEvent;
666 const static int CurrentStateChangedEvent;
667 const static int MediaErrorEvent;
668 const static int DownloadProgressChangedEvent;
669 const static int BufferingProgressChangedEvent;
671 // Registration functions
672 // This class takes ownership of the infos and will delete them (not free) when the Media is shutdown.
673 static void RegisterDemuxer (DemuxerInfo *info);
674 /* @GenerateCBinding */
675 static void RegisterDecoder (DecoderInfo *info);
676 static void RegisterConverter (ConverterInfo *info);
678 static void RegisterMSCodecs ();
679 static bool IsMSCodecsInstalled ();
681 static void Initialize ();
682 static void Shutdown ();
686 * MediaThreadPool
688 * The most important requirement for the thread pool is that it never executes several work items for a single Media instance simultaneously.
689 * It accomplishes this by having a list of Media instances which is currently being worked on, and whenever a thread is free, it finds work for
690 * a Media instance which is not in the list.
692 class MediaThreadPool {
693 private:
694 static pthread_mutex_t mutex;
695 static pthread_cond_t condition; /* signalled when work has been added */
696 static pthread_cond_t completed_condition; /* signalled when work has completed executing */
697 static const int max_threads = 4; /* max 4 threads for now */
698 static int count; // the number of created threads
699 static pthread_t threads [max_threads]; // array of threads
700 static bool valid [max_threads]; // specifies which thread indices are valid.
701 static Media *medias [max_threads]; // array of medias currently being worked on (indices corresponds to the threads array). Only one media can be worked on at the same time.
702 static Deployment *deployments [max_threads]; // array of deployments currently being worked on.
703 static bool shutting_down; // flag telling if we're shutting down (in which case no new threads should be created) - it's also used to check if we've been shut down already (i.e. it's not set to false when the shutdown has finished).
704 static List *queue;
706 static void *WorkerLoop (void *data);
708 public:
709 // Removes all enqueued work for the specified media.
710 static void RemoveWork (Media *media);
711 // Waits until all enqueued work for the specified deployment has finished
712 // executing and there is no more work for the specified deployment. Note that
713 // it does not touch the queue, it just waits for the threads to finish cleaning
714 // up the queue.
715 static void WaitForCompletion (Deployment *deployment); /* Main thread only */
716 static void AddWork (MediaClosure *closure, bool wakeup);
717 static void WakeUp ();
718 static void Initialize ();
719 static void Shutdown ();
721 // this method checks if the current thread is a thread-pool thread
722 static bool IsThreadPoolThread ();
725 class MediaFrame : public EventObject {
726 private:
727 void Initialize ();
729 protected:
730 virtual ~MediaFrame ();
732 public:
733 MediaFrame (IMediaStream *stream);
734 /* @GenerateCBinding,GeneratePInvoke */
735 MediaFrame (IMediaStream *stream, guint8 *buffer, guint32 buflen, guint64 pts, bool keyframe);
736 void Dispose ();
738 /* @GenerateCBinding */
739 void AddState (MediaFrameState state) { this->state |= (guint16) state; } // There's no way of "going back" to an earlier state
740 bool IsDecoded () { return (((MediaFrameState) state) & MediaFrameDecoded) == MediaFrameDecoded; }
741 bool IsDemuxed () { return (((MediaFrameState) state) & MediaFrameDemuxed) == MediaFrameDemuxed; }
742 bool IsConverted () { return (((MediaFrameState) state) & MediaFrameConverted) == MediaFrameConverted; }
743 bool IsPlanar () { return (((MediaFrameState) state) & MediaFramePlanar) == MediaFramePlanar; }
744 /* @GenerateCBinding */
745 bool IsKeyFrame () { return (((MediaFrameState) state) & MediaFrameKeyFrame) == MediaFrameKeyFrame; }
746 bool IsMarker () { return (((MediaFrameState) state) & MediaFrameMarker) == MediaFrameMarker; }
748 IMediaStream *stream;
749 MediaMarker *marker;
750 void *decoder_specific_data; // data specific to the decoder
751 guint64 pts; // Set by the demuxer
752 guint64 duration; // Set by the demuxer
754 guint16 state; // Current state of the frame
755 guint16 event; // special frame event if non-0
757 // The demuxer sets these to the encoded data which the
758 // decoder then uses and replaces with the decoded data.
759 guint8 *buffer;
760 guint32 buflen;
762 // planar data
763 guint8 *data_stride[4]; // Set by the decoder
764 int srcSlideY; // Set by the decoder
765 int srcSlideH; // Set by the decoder
766 int srcStride[4]; // Set by the decoder
768 // The decoded size of the frame (might be bigger or smaller than the size of the stream).
769 // 0 = the size specified in the stream
770 gint32 width;
771 gint32 height;
773 /* @GenerateCBinding */
774 guint32 GetBufLen () { return buflen; }
775 /* @GenerateCBinding */
776 void SetBufLen (guint32 value) { buflen = value; }
777 /* @GenerateCBinding */
778 guint8* GetBuffer () { return buffer; }
779 /* @GenerateCBinding */
780 void SetBuffer (guint8 *value) { buffer = value; }
781 /* @GenerateCBinding */
782 guint64 GetPts () { return pts; }
783 /* @GenerateCBinding */
784 void SetPts (guint64 value) { pts = value; }
786 /* @GenerateCBinding */
787 gint32 GetWidth () { return width; }
788 /* @GenerateCBinding */
789 void SetWidth (gint32 value) { width = value; }
790 /* @GenerateCBinding */
791 gint32 GetHeight () { return height; }
792 /* @GenerateCBinding */
793 void SetHeight (gint32 value) { height = value; }
794 /* @GenerateCBinding */
795 void SetDataStride (guint8 *a, guint8 *b, guint8 *c, guint8 *d);
796 /* @GenerateCBinding */
797 void SetSrcStride (int a, int b, int c, int d);
798 /* @GenerateCBinding */
799 void SetSrcSlideY (int value);
800 /* @GenerateCBinding */
801 void SetSrcSlideH (int value);
802 /* @GenerateCBinding */
803 void SetDecoderSpecificData (void *value) { decoder_specific_data = value; }
808 class MediaMarker : public EventObject {
809 guint64 pts; // 100-nanosecond units (pts)
810 char *type;
811 char *text;
813 protected:
814 virtual ~MediaMarker ();
816 public:
817 class Node : public List::Node {
818 public:
819 Node (MediaMarker *m)
821 marker = m;
822 marker->ref ();
825 virtual ~Node ()
827 marker->unref ();
830 MediaMarker *marker;
833 MediaMarker (const char *type, const char *text, guint64 pts);
835 const char *Type () { return type; }
836 const char *Text () { return text; }
837 guint64 Pts () { return pts; }
840 // Interfaces
842 class IMediaDemuxer : public IMediaObject {
843 private:
844 IMediaStream **streams;
845 int stream_count;
846 bool opened;
847 bool opening;
848 bool seeking; /* Only media thread may access, no lock required. When set, the demuxer should not request new frames */
850 * Set on main thread, read/reset on media thread: access needs mutex locked.
851 * When a seek is pending, indicates the position we should seek to. We specifically
852 * do not enqueue the pts with the seek request - this would cause
853 * multiple seeks with unpredictable ordeing when SeekAsync is called again before the
854 * first seek has finished
856 guint64 seeking_pts;
857 IMediaStream *pending_stream; // the stream we're waiting for a frame for. media thread only.
858 bool pending_fill_buffers;
859 Mutex mutex;
861 static MediaResult ReportSeekCompletedCallback (MediaClosure *closure);
862 static MediaResult ReportGetFrameCompletedCallback (MediaClosure *closure);
863 static MediaResult GetFrameCallback (MediaClosure *closure);
864 static MediaResult FillBuffersCallback (MediaClosure *closure);
865 static MediaResult OpenCallback (MediaClosure *closure);
866 static MediaResult SeekCallback (MediaClosure *closure);
868 void FillBuffersInternal ();
870 protected:
871 IMediaSource *source;
873 IMediaDemuxer (Type::Kind kind, Media *media, IMediaSource *source);
874 IMediaDemuxer (Type::Kind kind, Media *media);
876 virtual ~IMediaDemuxer () {}
878 void SetStreams (IMediaStream **streams, int count);
879 gint32 AddStream (IMediaStream *stream);
881 virtual void CloseDemuxerInternal () {};
882 virtual void GetDiagnosticAsyncInternal (MediaStreamSourceDiagnosticKind diagnosticKind) {}
883 virtual void GetFrameAsyncInternal (IMediaStream *stream) = 0;
884 virtual void OpenDemuxerAsyncInternal () = 0;
885 virtual void SeekAsyncInternal (guint64 pts) = 0;
886 virtual void SwitchMediaStreamAsyncInternal (IMediaStream *stream) = 0;
888 void EnqueueOpen ();
889 void EnqueueReportSeekCompleted (guint64 pts);
890 void EnqueueGetFrame (IMediaStream *stream);
891 void EnqueueReportGetFrameCompleted (MediaFrame *frame);
892 /* Re-enqueue the seek. */
893 void EnqueueSeek ();
894 void SeekAsync ();
896 public:
897 virtual void Dispose ();
899 void CloseDemuxer () {};
900 void GetDiagnosticAsync (MediaStreamSourceDiagnosticKind diagnosticKind) {}
901 void GetFrameAsync (IMediaStream *stream);
902 void OpenDemuxerAsync ();
903 /* Might not seek immediately, It will wait until there are no pending frames. */
904 void SeekAsync (guint64 pts);
905 void SwitchMediaStreamAsync (IMediaStream *stream);
907 /* @GenerateCBinding,GeneratePInvoke */
908 void ReportOpenDemuxerCompleted ();
909 /* @GenerateCBinding,GeneratePInvoke */
910 void ReportGetFrameCompleted (MediaFrame *frame);
911 /* @GenerateCBinding,GeneratePInvoke */
912 void ReportGetFrameProgress (double bufferingProgress);
913 /* @GenerateCBinding,GeneratePInvoke */
914 void ReportSeekCompleted (guint64 pts);
915 /* @GenerateCBinding,GeneratePInvoke */
916 void ReportSwitchMediaStreamCompleted (IMediaStream *stream);
917 /* @GenerateCBinding,GeneratePInvoke */
918 void ReportGetDiagnosticCompleted (MediaStreamSourceDiagnosticKind diagnosticKind, gint64 diagnosticValue);
920 guint64 GetBufferedSize ();
921 void FillBuffers ();
922 void ClearBuffers ();
924 void PrintBufferInformation ();
926 int GetStreamCount () { return stream_count; }
927 IMediaStream *GetStream (int index);
928 // Gets the longest duration from all the streams
929 virtual guint64 GetDuration (); // 100-nanosecond units (pts)
930 virtual const char *GetName () = 0;
931 virtual void UpdateSelected (IMediaStream *stream) {};
933 guint64 GetLastAvailablePts ();
934 IMediaSource *GetSource () { return source; }
935 bool IsOpened () { return opened; }
936 bool IsOpening () { return opening; }
938 virtual bool IsPlaylist () { return false; }
939 virtual Playlist *GetPlaylist () { return NULL; }
942 class IMediaDecoder : public IMediaObject {
943 private:
944 bool opening;
945 bool opened;
946 bool input_ended;
947 MoonPixelFormat pixel_format; // The pixel format this codec outputs. Open () should fill this in.
948 IMediaStream *stream;
949 Queue queue; // the list of frames to decode.
951 static MediaResult DecodeFrameCallback (MediaClosure *closure);
953 class FrameNode : public List::Node {
954 public:
955 MediaFrame *frame;
957 FrameNode (MediaFrame *f) : frame (f)
959 frame->ref ();
962 virtual ~FrameNode ()
964 frame->unref ();
968 protected:
969 virtual ~IMediaDecoder () {}
972 * Called when a frame needs to get decoded. The implementation needs to call
973 * ReportDecodeFrameCompleted at least once for each DecodeFrameAsync request
974 * (calling ReportDecodeFrameCompleted more than once for each DecodeFrameAsync
975 * request is allowed). The implementation may call ReportDecodeFrameCompleted
976 * with a null buffer (for instance if it does not have enough input to produce output).
978 virtual void DecodeFrameAsyncInternal (MediaFrame *frame) = 0;
979 virtual void OpenDecoderAsyncInternal () = 0;
981 // InputEnded is called when there is no more input. If the codec has delayed frames,
982 // it must call ReportDecodeFrameCompleted with those frames (all of them).
983 virtual void InputEnded () { };
985 public:
986 IMediaDecoder (Type::Kind kind, Media *media, IMediaStream *stream);
987 virtual void Dispose ();
989 // If MediaFrame->decoder_specific_data is non-NULL, this method is called in ~MediaFrame.
990 virtual void Cleanup (MediaFrame *frame) {}
991 virtual void CleanState () {}
992 virtual bool HasDelayedFrame () { return false; }
994 virtual const char *GetName () { return GetTypeName (); }
996 // This method is called when the demuxer has finished seeking.
997 void ReportSeekCompleted ();
998 // This method is called when the demuxer is out of data.
999 void ReportInputEnded ();
1000 /* @GenerateCBinding */
1001 void ReportDecodeFrameCompleted (MediaFrame *frame);
1002 /* @GenerateCBinding */
1003 void ReportOpenDecoderCompleted ();
1004 /* @GenerateCBinding */
1005 void SetPixelFormat (MoonPixelFormat value) { pixel_format = value; }
1007 void DecodeFrameAsync (MediaFrame *frame, bool enqueue_always);
1008 void OpenDecoderAsync ();
1010 bool IsOpening () { return opening; }
1011 bool IsOpened () { return opened; }
1012 MoonPixelFormat GetPixelFormat () { return pixel_format; }
1013 IMediaStream *GetStream () { return stream; }
1015 bool IsDecoderQueueEmpty () { return queue.IsEmpty (); }
1020 * Inherit from this class to provide image converters (yuv->rgb for instance)
1022 class IImageConverter : public IMediaObject {
1023 protected:
1024 virtual ~IImageConverter () {}
1026 public:
1027 MoonPixelFormat output_format;
1028 MoonPixelFormat input_format;
1029 VideoStream *stream;
1031 IImageConverter (Type::Kind kind, Media *media, VideoStream *stream);
1033 virtual MediaResult Open () = 0;
1034 virtual MediaResult Convert (guint8 *src[], int srcStride[], int srcSlideY, int srcSlideH, guint8 *dest[], int dstStride []) = 0;
1038 * IMediaSource
1040 class IMediaSource : public IMediaObject {
1041 private:
1042 // General locking behaviour:
1043 // All protected virtual methods must be called with the mutex
1044 // locked. If a derived virtual method needs to lock, it needs
1045 // to be implemented as a protected virtual method xxxInternal
1046 // which requires the mutex to be locked, and then a public
1047 // method in IMediaSource which does the locking. No public method
1048 // in IMediaSource may be called from the xxxInternal methods.
1049 pthread_mutex_t mutex;
1050 pthread_cond_t condition;
1052 protected:
1053 virtual ~IMediaSource ();
1055 void Lock ();
1056 void Unlock ();
1058 // All these methods must/will be called with the lock locked.
1059 virtual gint32 ReadInternal (void *buf, guint32 n);
1060 virtual gint32 PeekInternal (void *buf, guint32 n);
1061 virtual bool SeekInternal (gint64 offset, int mode);
1062 virtual gint64 GetLastAvailablePositionInternal () { return -1; }
1063 virtual gint64 GetPositionInternal ();
1064 virtual gint64 GetSizeInternal ();
1066 public:
1067 IMediaSource (Type::Kind kind, Media *media);
1068 virtual void Dispose ();
1070 // Initializes this stream (and if it succeeds, it can be read from later on).
1071 // streams based on remote content (live/progress) should contact the server
1072 // and try to start downloading content
1073 // file streams should try to open the file
1074 virtual MediaResult Initialize () = 0;
1075 virtual MediaSourceType GetType () = 0;
1077 // Reads 'n' bytes into 'buf'. If data isn't available it will
1078 // read the amount of data available. Returns the number of bytes read.
1079 // This method will lock the mutex.
1080 gint32 ReadSome (void *buf, guint32 n);
1082 // Reads 'n' bytes into 'buf'.
1083 // Returns false if 'n' bytes couldn't be read.
1084 // This method will lock the mutex.
1085 bool ReadAll (void *buf, guint32 n);
1087 // Reads 'n' bytes into 'buf', starting at position 'start'. If 'start' is -1,
1088 // then start at the current position. If data isn't available it will
1089 // read the amount of data available. Returns false if 'n' bytes couldn't be
1090 // read.
1091 // This method will lock the mutex.
1092 bool Peek (void *buf, guint32 n);
1094 virtual bool CanSeek () { return true; }
1096 // Seeks to the specified 'offset', using the specified 'mode'.
1097 // This method will lock the mutex.
1098 bool Seek (gint64 offset, int mode = SEEK_CUR);
1100 // Seeks to the specified 'pts'.
1101 virtual bool CanSeekToPts () { return false; }
1102 virtual MediaResult SeekToPts (guint64 pts) { return MEDIA_FAIL; }
1104 // Returns the current reading position
1105 // This method will lock the mutex.
1106 gint64 GetPosition ();
1108 // Returns the size of the source. This method may return -1 if the
1109 // size isn't known.
1110 // This method will lock the mutex.
1111 gint64 GetSize ();
1113 virtual bool Eof () = 0;
1115 // Returns the last available position
1116 // If the returned value is -1, then everything is available.
1117 // This method will lock the mutex.
1118 gint64 GetLastAvailablePosition ();
1120 // Checks if the specified position can be read
1121 // upon return, and if the position is not availble eof determines whether the position is not available because
1122 // the file isn't that big (eof = true), or the position hasn't been read yet (eof = false).
1123 // if the position is available, eof = false
1124 bool IsPositionAvailable (gint64 position, bool *eof);
1126 // If the derived class knows which demuxer it needs,
1127 // it should override this method and return a new demuxer.
1128 virtual IMediaDemuxer *CreateDemuxer (Media *media) { return NULL; }
1130 virtual const char *ToString () { return "IMediaSource"; }
1133 class ManagedStreamSource : public IMediaSource {
1134 private:
1135 ManagedStreamCallbacks stream;
1137 protected:
1138 virtual ~ManagedStreamSource ();
1140 virtual gint32 ReadInternal (void *buf, guint32 n);
1141 virtual gint32 PeekInternal (void *buf, guint32 n);
1142 virtual bool SeekInternal (gint64 offset, int mode);
1143 virtual gint64 GetPositionInternal ();
1144 virtual gint64 GetSizeInternal ();
1146 public:
1147 ManagedStreamSource (Media *media, ManagedStreamCallbacks *stream);
1149 virtual MediaResult Initialize () { return MEDIA_SUCCESS; }
1150 virtual MediaSourceType GetType () { return MediaSourceTypeManagedStream; }
1152 virtual bool Eof () { return GetPositionInternal () == GetSizeInternal (); }
1154 virtual const char *ToString () { return GetTypeName (); }
1157 class FileSource : public IMediaSource {
1158 public: // private:
1159 gint64 size;
1160 FILE *fd;
1161 bool temp_file;
1162 char buffer [1024];
1164 void UpdateSize ();
1165 protected:
1166 char *filename;
1168 virtual ~FileSource ();
1169 FileSource (Media *media, bool temp_file);
1171 MediaResult Open (const char *filename);
1173 virtual gint32 ReadInternal (void *buf, guint32 n);
1174 virtual gint32 PeekInternal (void *buf, guint32 n);
1175 virtual bool SeekInternal (gint64 offset, int mode);
1176 virtual gint64 GetPositionInternal ();
1177 virtual gint64 GetSizeInternal ();
1179 public:
1180 FileSource (Media *media, const char *filename);
1181 virtual void Dispose ();
1183 virtual MediaResult Initialize ();
1184 virtual MediaSourceType GetType () { return MediaSourceTypeFile; }
1186 virtual bool Eof ();
1188 virtual const char *ToString () { return filename; }
1190 const char *GetFileName () { return filename; }
1193 class ProgressiveSource : public FileSource {
1194 private:
1195 gint64 write_pos;
1196 gint64 size;
1197 // To avoid locking while reading and writing (since reading is done on
1198 // the media thread and writing on the main thread), we open two file
1199 // handlers, one for reading (in FileSource) and the other one here
1200 // for writing.
1201 FILE *write_fd;
1202 char *uri;
1203 Cancellable *cancellable;
1205 virtual gint64 GetLastAvailablePositionInternal () { return size == write_pos ? write_pos : write_pos & ~(1024*4-1); }
1206 virtual gint64 GetSizeInternal () { return size; }
1208 static void data_write (void *data, gint32 offset, gint32 n, void *closure);
1209 static void notify_func (NotifyType type, gint64 args, void *closure);
1210 static void delete_cancellable (EventObject *data);
1212 void Notify (NotifyType, gint64 args);
1214 void DownloadComplete ();
1215 void DownloadFailed ();
1216 void DataWrite (void *data, gint32 offset, gint32 n);
1217 void NotifySize (gint64 size);
1218 void SetTotalSize (gint64 size);
1220 void CloseWriteFile ();
1222 protected:
1223 virtual ~ProgressiveSource () {}
1225 public:
1226 ProgressiveSource (Media *media, const char *uri);
1227 virtual void Dispose ();
1229 virtual MediaResult Initialize ();
1230 virtual MediaSourceType GetType () { return MediaSourceTypeProgressive; }
1234 * MemorySource
1236 class MemorySource : public IMediaSource {
1237 private:
1238 void *memory;
1239 gint32 size;
1240 gint64 start;
1241 gint64 pos;
1242 bool owner;
1244 protected:
1245 virtual ~MemorySource ();
1247 virtual gint32 ReadInternal (void *buf, guint32 n);
1248 virtual gint32 PeekInternal (void *buf, guint32 n);
1249 virtual bool SeekInternal (gint64 offset, int mode);
1250 virtual gint64 GetSizeInternal () { return size; }
1251 virtual gint64 GetPositionInternal () { return pos + start; }
1252 virtual gint64 GetLastAvailablePositionInternal () { return start + size; }
1254 public:
1255 MemorySource (Media *media, void *memory, gint32 size, gint64 start = 0, bool owner = true);
1257 void *GetMemory () { return memory; }
1258 void Release (void) { delete this; }
1260 void SetOwner (bool value) { owner = value; }
1261 gint64 GetStart () { return start; }
1263 virtual MediaResult Initialize () { return MEDIA_SUCCESS; }
1264 virtual MediaSourceType GetType () { return MediaSourceTypeMemory; }
1266 virtual bool CanSeek () { return true; }
1267 virtual bool Eof () { return pos >= size; }
1269 virtual const char *ToString () { return "MemorySource"; }
1272 class VideoStream : public IMediaStream {
1273 protected:
1274 virtual ~VideoStream ();
1276 public:
1277 void Dispose ();
1279 IImageConverter *converter; // This stream has the ownership of the converter, it will be deleted upon destruction.
1280 guint32 bits_per_sample;
1281 guint64 pts_per_frame; // Duration (in pts) of each frame. Set to 0 if unknown.
1282 guint64 initial_pts;
1283 guint32 height;
1284 guint32 width;
1285 guint32 bit_rate;
1287 VideoStream (Media *media);
1289 /* @GenerateCBinding,GeneratePInvoke */
1290 VideoStream (Media *media, int codec_id, guint32 width, guint32 height, guint64 duration, gpointer extra_data, guint32 extra_data_size);
1292 virtual MediaStreamType GetType () { return MediaTypeVideo; }
1294 guint32 GetBitsPerSample () { return bits_per_sample; }
1295 guint32 GetPtsPerFrame () { return pts_per_frame; }
1296 guint32 GetInitialPts () { return initial_pts; }
1297 /* @GenerateCBinding */
1298 guint32 GetWidth () { return width; }
1299 /* @GenerateCBinding */
1300 guint32 GetHeight () { return height; }
1301 guint32 GetBitRate () { return bit_rate; }
1304 class AudioStream : public IMediaStream {
1305 private:
1306 /* input format */
1307 int input_bits_per_sample;
1308 int input_block_align;
1309 int input_sample_rate;
1310 int input_channels;
1311 int input_bit_rate;
1313 /* output format */
1314 int output_bits_per_sample;
1315 int output_block_align;
1316 int output_sample_rate;
1317 int output_channels;
1318 int output_bit_rate;
1319 protected:
1320 virtual ~AudioStream () {}
1322 public:
1324 AudioStream (Media *media);
1326 /* @GenerateCBinding,GeneratePInvoke */
1327 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);
1329 virtual MediaStreamType GetType () { return MediaTypeAudio; }
1331 // TODO: remove the non Input/Output accessors
1332 // wait until later since it is a two-way codec abi breakage.
1334 /* @GenerateCBinding */
1335 int GetBitsPerSample () { return input_bits_per_sample; }
1336 /* @GenerateCBinding */
1337 void SetBitsPerSample (int value) { output_bits_per_sample = input_bits_per_sample = value; }
1338 /* @GenerateCBinding */
1339 int GetBlockAlign () { return input_block_align; }
1340 /* @GenerateCBinding */
1341 void SetBlockAlign (int value) { output_block_align = input_block_align = value; }
1342 /* @GenerateCBinding */
1343 int GetSampleRate () { return input_sample_rate; }
1344 /* @GenerateCBinding */
1345 void SetSampleRate (int value) { output_sample_rate = input_sample_rate = value; }
1346 /* @GenerateCBinding */
1347 int GetChannels () { return input_channels; }
1348 /* @GenerateCBinding */
1349 void SetChannels (int value) { output_channels = input_channels = value; }
1350 /* @GenerateCBinding */
1351 int GetBitRate () { return input_bit_rate; }
1352 /* @GenerateCBinding */
1353 void SetBitRate (int value) { output_bit_rate = input_bit_rate = value; }
1355 // input accessors
1357 /* @GenerateCBinding */
1358 int GetInputBitsPerSample () { return input_bits_per_sample; }
1359 /* @GenerateCBinding */
1360 void SetInputBitsPerSample (int value) { input_bits_per_sample = value; }
1362 /* @GenerateCBinding */
1363 int GetInputBlockAlign () { return input_block_align; }
1364 /* @GenerateCBinding */
1365 void SetInputBlockAlign (int value) { input_block_align = value; }
1367 /* @GenerateCBinding */
1368 int GetInputSampleRate () { return input_sample_rate; }
1369 /* @GenerateCBinding */
1370 void SetInputSampleRate (int value) { input_sample_rate = value; }
1372 /* @GenerateCBinding */
1373 int GetInputChannels () { return input_channels; }
1374 /* @GenerateCBinding */
1375 void SetInputChannels (int value) { input_channels = value; }
1377 /* @GenerateCBinding */
1378 int GetInputBitRate () { return input_bit_rate; }
1379 /* @GenerateCBinding */
1380 void SetInputBitRate (int value) { input_bit_rate = value; }
1382 // output accessors
1384 /* @GenerateCBinding */
1385 int GetOutputBitsPerSample () { return output_bits_per_sample; }
1386 /* @GenerateCBinding */
1387 void SetOutputBitsPerSample (int value) { output_bits_per_sample = value; }
1389 /* @GenerateCBinding */
1390 int GetOutputBlockAlign () { return output_block_align; }
1391 /* @GenerateCBinding */
1392 void SetOutputBlockAlign (int value) { output_block_align = value; }
1394 /* @GenerateCBinding */
1395 int GetOutputSampleRate () { return output_sample_rate; }
1396 /* @GenerateCBinding */
1397 void SetOutputSampleRate (int value) { output_sample_rate = value; }
1399 /* @GenerateCBinding */
1400 int GetOutputChannels () { return output_channels; }
1401 /* @GenerateCBinding */
1402 void SetOutputChannels (int value) { output_channels = value; }
1404 /* @GenerateCBinding */
1405 int GetOutputBitRate () { return output_bit_rate; }
1406 /* @GenerateCBinding */
1407 void SetOutputBitRate (int value) { output_bit_rate = value; }
1411 * ExternalDemuxer
1414 /* @CBindingRequisite */
1415 typedef void (* CloseDemuxerCallback) (void *instance);
1416 /* @CBindingRequisite */
1417 typedef void (* GetDiagnosticAsyncCallback) (void *instance, int /*MediaStreamSourceDiagnosticKind*/ diagnosticKind);
1418 /* @CBindingRequisite */
1419 typedef void (* GetFrameAsyncCallback) (void *instance, int /*MediaStreamType*/ mediaStreamType);
1420 /* @CBindingRequisite */
1421 typedef void (* OpenDemuxerAsyncCallback) (void *instance, IMediaDemuxer *demuxer);
1422 /* @CBindingRequisite */
1423 typedef void (* SeekAsyncCallback) (void *instance, guint64 seekToTime);
1424 /* @CBindingRequisite */
1425 typedef void (* SwitchMediaStreamAsyncCallback) (void *instance, IMediaStream *mediaStreamDescription);
1427 class ExternalDemuxer : public IMediaDemuxer {
1428 private:
1429 void *instance;
1430 pthread_rwlock_t rwlock;
1431 CloseDemuxerCallback close_demuxer_callback;
1432 GetDiagnosticAsyncCallback get_diagnostic_async_callback;
1433 GetFrameAsyncCallback get_sample_async_callback;
1434 OpenDemuxerAsyncCallback open_demuxer_async_callback;
1435 SeekAsyncCallback seek_async_callback;
1436 SwitchMediaStreamAsyncCallback switch_media_stream_async_callback;
1438 protected:
1439 virtual ~ExternalDemuxer ();
1441 virtual void CloseDemuxerInternal ();
1442 virtual void GetDiagnosticAsyncInternal (MediaStreamSourceDiagnosticKind diagnosticsKind);
1443 virtual void GetFrameAsyncInternal (IMediaStream *stream);
1444 virtual void OpenDemuxerAsyncInternal ();
1445 virtual void SeekAsyncInternal (guint64 seekToTime);
1446 virtual void SwitchMediaStreamAsyncInternal (IMediaStream *mediaStreamDescription);
1448 public:
1449 ExternalDemuxer (Media *media, void *instance, CloseDemuxerCallback close_demuxer,
1450 GetDiagnosticAsyncCallback get_diagnostic, GetFrameAsyncCallback get_sample, OpenDemuxerAsyncCallback open_demuxer,
1451 SeekAsyncCallback seek, SwitchMediaStreamAsyncCallback switch_media_stream);
1453 virtual void Dispose ();
1455 /* @GenerateCBinding,GeneratePInvoke */
1456 void SetCanSeek (bool value);
1458 /* @GenerateCBinding,GeneratePInvoke */
1459 void ClearCallbacks (); /* thread-safe */
1461 /* @GenerateCBinding,GeneratePInvoke */
1462 gint32 AddStream (IMediaStream *stream);
1464 virtual const char *GetName () { return "ExternalDemuxer"; }
1468 * ExternalDecoder
1471 /* @CBindingRequisite */
1472 typedef void (* ExternalDecoder_DecodeFrameAsyncCallback) (void *instance, MediaFrame *frame);
1473 /* @CBindingRequisite */
1474 typedef void (* ExternalDecoder_OpenDecoderAsyncCallback) (void *instance);
1475 /* @CBindingRequisite */
1476 typedef void (* ExternalDecoder_CleanupCallback) (void *instance, MediaFrame *frame);
1477 /* @CBindingRequisite */
1478 typedef void (* ExternalDecoder_CleanStateCallback) (void *instance);
1479 /* @CBindingRequisite */
1480 typedef bool (* ExternalDecoder_HasDelayedFrameCallback) (void *instance);
1481 /* @CBindingRequisite */
1482 typedef void (* ExternalDecoder_DisposeCallback) (void *instance);
1483 /* @CBindingRequisite */
1484 typedef void (* ExternalDecoder_DtorCallback) (void *instance);
1486 class ExternalDecoder : public IMediaDecoder {
1487 private:
1488 void *instance;
1489 char *name;
1490 ExternalDecoder_DecodeFrameAsyncCallback decode_frame_async;
1491 ExternalDecoder_OpenDecoderAsyncCallback open_decoder_async;
1492 ExternalDecoder_CleanupCallback cleanup;
1493 ExternalDecoder_CleanStateCallback clean_state;
1494 ExternalDecoder_HasDelayedFrameCallback has_delayed_frame;
1495 ExternalDecoder_DisposeCallback dispose;
1496 ExternalDecoder_DtorCallback dtor;
1498 protected:
1499 virtual ~ExternalDecoder ();
1501 virtual void DecodeFrameAsyncInternal (MediaFrame *frame);
1502 virtual void OpenDecoderAsyncInternal ();
1504 virtual void InputEnded ();
1505 public:
1506 /* @GenerateCBinding */
1507 ExternalDecoder (Media *media, IMediaStream *stream, void *instance, const char *name,
1508 ExternalDecoder_DecodeFrameAsyncCallback decode_frame_async,
1509 ExternalDecoder_OpenDecoderAsyncCallback open_decoder_async,
1510 ExternalDecoder_CleanupCallback cleanup,
1511 ExternalDecoder_CleanStateCallback clean_state,
1512 ExternalDecoder_HasDelayedFrameCallback has_delayed_frame,
1513 ExternalDecoder_DisposeCallback dispose,
1514 ExternalDecoder_DtorCallback dtor);
1516 virtual void Dispose ();
1518 public:
1519 // If MediaFrame->decoder_specific_data is non-NULL, this method is called in ~MediaFrame.
1520 virtual void Cleanup (MediaFrame *frame);
1521 virtual void CleanState ();
1522 virtual bool HasDelayedFrame ();
1524 virtual const char *GetName () { return name; }
1528 * ExternalDecoderInfo
1531 /* @CBindingRequisite */
1532 typedef bool (* ExternalDecoderInfo_SupportsCallback) (void *instance, const char *codec);
1533 /* @CBindingRequisite */
1534 typedef IMediaDecoder * (* ExternalDecoderInfo_Create) (void *instance, Media *media, IMediaStream *stream);
1535 /* @CBindingRequisite */
1536 typedef void (* ExternalDecoderInfo_dtor) (void *instance);
1538 class ExternalDecoderInfo : public DecoderInfo {
1539 private:
1540 void *instance;
1541 char *name;
1542 ExternalDecoderInfo_SupportsCallback supports;
1543 ExternalDecoderInfo_Create create;
1544 ExternalDecoderInfo_dtor dtor;
1546 public:
1547 /* @GenerateCBinding */
1548 ExternalDecoderInfo (void *instance, const char *name, ExternalDecoderInfo_SupportsCallback supports, ExternalDecoderInfo_Create create, ExternalDecoderInfo_dtor dtor);
1550 virtual bool Supports (const char *codec);
1551 virtual IMediaDecoder *Create (Media *media, IMediaStream *stream);
1553 virtual ~ExternalDecoderInfo ();
1555 virtual const char *GetName () { return name; }
1559 * ASX demuxer
1561 class ASXDemuxer : public IMediaDemuxer {
1562 private:
1563 Playlist *playlist;
1565 protected:
1566 virtual ~ASXDemuxer ();
1567 virtual MediaResult SeekInternal (guint64 pts) { return MEDIA_FAIL; }
1569 virtual void GetFrameAsyncInternal (IMediaStream *stream) { ReportErrorOccurred ("GetFrameAsync isn't supported for ASXDemuxer"); }
1570 virtual void OpenDemuxerAsyncInternal ();
1571 virtual void SeekAsyncInternal (guint64 seekToTime) {}
1572 virtual void SwitchMediaStreamAsyncInternal (IMediaStream *stream) {}
1574 public:
1575 ASXDemuxer (Media *media, IMediaSource *source);
1576 virtual void Dispose ();
1578 virtual bool IsPlaylist () { return true; }
1579 virtual Playlist *GetPlaylist () { return playlist; }
1580 virtual const char *GetName () { return "ASXDemuxer"; }
1583 class ASXDemuxerInfo : public DemuxerInfo {
1584 public:
1585 virtual MediaResult Supports (IMediaSource *source);
1586 virtual IMediaDemuxer *Create (Media *media, IMediaSource *source);
1587 virtual const char *GetName () { return "ASXDemuxer"; }
1590 class MarkerStream : public IMediaStream {
1591 private:
1592 MediaMarkerFoundClosure *closure;
1593 Mutex mutex;
1594 List list; // a list of markers found while there were no callback.
1596 protected:
1597 virtual ~MarkerStream () {}
1599 public:
1600 MarkerStream (Media *media);
1601 virtual void Dispose ();
1603 virtual MediaStreamType GetType () { return MediaTypeMarker; }
1605 void SetCallback (MediaMarkerFoundClosure *closure);
1607 // Since the markers are taking the wrong way through the pipeline
1608 // (it's the pipeline who is pushing the markers up to the consumer,
1609 // not the consumer reading new markers), this works in the following way:
1610 // The demuxer reaches a marker somehow, creates a MediaFrame with the marker data and calls MarkerFound on the MarkerStream.
1611 // The MarkerStream calls the decoder to decode the frame.
1612 // The decoder must create an instance of MediaMarker and store it in the frame's buffer.
1613 // The MarkerStream then calls the closure with the MediaMarker.
1614 // Cleanup:
1615 // - The stream (in MarkerFound) frees the MediaMarker.
1616 // - The demuxer frees the MediaFrame, and the original frame buffer (before decoding).
1617 void MarkerFound (MediaFrame *frame);
1619 virtual void FrameEnqueued ();
1620 MediaMarker *Pop ();
1623 class PassThroughDecoder : public IMediaDecoder {
1624 protected:
1625 virtual ~PassThroughDecoder () {}
1626 virtual void DecodeFrameAsyncInternal (MediaFrame *frame);
1627 virtual void OpenDecoderAsyncInternal ();
1629 public:
1630 PassThroughDecoder (Media *media, IMediaStream *stream);
1631 virtual void Dispose ();
1633 virtual const char *GetName () { return "PassThroughDecoder"; }
1636 class PassThroughDecoderInfo : public DecoderInfo {
1637 public:
1638 virtual bool Supports (const char *codec);
1639 virtual IMediaDecoder *Create (Media *media, IMediaStream *stream)
1641 return new PassThroughDecoder (media, stream);
1643 virtual const char *GetName () { return "PassThroughDecoder"; }
1646 class NullDecoder : public IMediaDecoder {
1647 private:
1648 // Video data
1649 guint8 *logo;
1650 guint32 logo_size;
1652 // Audio datarf
1653 guint64 prev_pts;
1655 MediaResult DecodeVideoFrame (MediaFrame *frame);
1656 MediaResult DecodeAudioFrame (MediaFrame *frame);
1657 MediaResult OpenAudio ();
1658 MediaResult OpenVideo ();
1660 protected:
1661 virtual ~NullDecoder () {}
1662 virtual void DecodeFrameAsyncInternal (MediaFrame *frame);
1663 virtual void OpenDecoderAsyncInternal ();
1665 public:
1666 NullDecoder (Media *media, IMediaStream *stream);
1667 virtual void Dispose ();
1669 virtual const char *GetName () { return "NullDecoder"; }
1672 class NullDecoderInfo : public DecoderInfo {
1673 public:
1674 virtual bool Supports (const char *codec);
1676 virtual IMediaDecoder *Create (Media *media, IMediaStream *stream)
1678 return new NullDecoder (media, stream);
1680 virtual const char *GetName () { return "NullDecoder"; }
1683 #endif