2009-12-01 Jeffrey Stedfast <fejj@novell.com>
[moon.git] / src / pipeline.h
blob2d327fb335bdb4ae24a3888b9d3b125b7a8dc1a8
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);
43 class Media;
44 class IMediaSource;
45 class IMediaStream;
46 class IMediaDemuxer;
47 class IMediaDecoder;
48 class IMediaObject;
49 class FileSource;
50 class LiveSource;
51 class MediaClosure;
52 class MediaFrame;
53 class VideoStream;
54 class AudioStream;
55 class MarkerStream;
56 class IImageConverter;
57 class MediaMarker;
58 class ProgressiveSource;
59 class MediaMarkerFoundClosure;
60 class Playlist;
62 typedef gint32 MediaResult;
64 #define MEDIA_SUCCESS ((MediaResult) 0)
65 #define MEDIA_FAIL ((MediaResult) 1)
66 #define MEDIA_INVALID_STREAM ((MediaResult) 2)
67 #define MEDIA_UNKNOWN_CODEC ((MediaResult) 3)
68 #define MEDIA_INVALID_MEDIA ((MediaResult) 4)
69 #define MEDIA_FILE_ERROR ((MediaResult) 5)
70 #define MEDIA_CODEC_ERROR ((MediaResult) 6)
71 #define MEDIA_OUT_OF_MEMORY ((MediaResult) 7)
72 #define MEDIA_DEMUXER_ERROR ((MediaResult) 8)
73 #define MEDIA_CONVERTER_ERROR ((MediaResult) 9)
74 #define MEDIA_UNKNOWN_CONVERTER ((MediaResult) 10)
75 #define MEDIA_UNKNOWN_MEDIA_TYPE ((MediaResult) 11)
76 #define MEDIA_CODEC_DELAYED ((MediaResult) 12)
77 #define MEDIA_NO_MORE_DATA ((MediaResult) 13)
78 #define MEDIA_CORRUPTED_MEDIA ((MediaResult) 14)
79 #define MEDIA_NO_CALLBACK ((MediaResult) 15)
80 #define MEDIA_INVALID_DATA ((MediaResult) 16)
81 #define MEDIA_READ_ERROR ((MediaResult) 17)
82 // The pipeline returns this value in GetNextFrame if the
83 // buffer is empty.
84 #define MEDIA_BUFFER_UNDERFLOW ((MediaResult) 18)
85 // This value might be returned by the pipeline for an open
86 // request, indicating that there is not enough data available
87 // to open the media.
88 // It is also used internally in the pipeline whenever something
89 // can't be done because of not enough data.
90 // Note: this value must not be used for eof condition.
91 #define MEDIA_NOT_ENOUGH_DATA ((MediaResult) 19)
92 #define MEDIA_INVALID ((MediaResult) 0xFFFFFFFF)
94 #define MEDIA_SUCCEEDED(x) (((x) <= 0))
96 typedef MediaResult MediaCallback (MediaClosure *closure);
98 #include "list.h"
99 #include "debug.h"
100 #include "dependencyobject.h"
101 #include "error.h"
102 #include "type.h"
103 #include "enums.h"
104 #include "application.h"
107 * MediaClosure:
109 class MediaClosure : public EventObject {
110 private:
111 MediaCallback *callback;
112 MediaResult result;
114 Media *media;
115 EventObject *context; // The property of whoever creates the closure.
116 const char *description;
117 void Init (Media *media, MediaCallback *callback, EventObject *context);
119 protected:
120 virtual ~MediaClosure () {}
121 MediaClosure (Type::Kind object_type, Media *media, MediaCallback *callback, EventObject *context);
123 public:
124 MediaClosure (Media *media, MediaCallback *callback, EventObject *context, const char *description);
125 virtual void Dispose ();
127 void Call (); // Calls the callback and stores the result in 'result', then calls the 'finished' callback
129 bool CallExecuted () { return result != MEDIA_INVALID; }
131 MediaResult GetResult () { return result; }
132 Media *GetMedia () { return media; }
133 EventObject *GetContext () { return context; }
134 const char *GetDescription () { return description != NULL ? description : GetTypeName (); }
138 * MediaDisposeObjectClosure
140 class MediaDisposeObjectClosure : public MediaClosure {
141 public:
142 MediaDisposeObjectClosure (Media *media, MediaCallback *callback, EventObject *context);
143 virtual void Dispose ();
147 * MediaReportSeekCompletedClosure
149 class MediaReportSeekCompletedClosure : public MediaClosure {
150 private:
151 guint64 pts;
153 protected:
154 virtual ~MediaReportSeekCompletedClosure ();
156 public:
157 MediaReportSeekCompletedClosure (Media *media, MediaCallback *callback, IMediaDemuxer *context, guint64 pts);
158 virtual void Dispose ();
160 guint64 GetPts () { return pts; }
161 IMediaDemuxer *GetDemuxer () { return (IMediaDemuxer *) GetContext (); }
165 * MediaGetFrameClosure
167 class MediaGetFrameClosure : public MediaClosure {
168 private:
169 IMediaStream *stream;
171 protected:
172 virtual ~MediaGetFrameClosure ();
174 public:
175 MediaGetFrameClosure (Media *media, MediaCallback *callback, IMediaDemuxer *context, IMediaStream *stream);
176 virtual void Dispose ();
178 IMediaStream *GetStream () { return stream; }
179 IMediaDemuxer *GetDemuxer () { return (IMediaDemuxer *) GetContext (); }
183 * MediaReportFrameCompletedClosure
185 class MediaReportFrameCompletedClosure : public MediaClosure {
186 private:
187 MediaFrame *frame;
189 protected:
190 virtual ~MediaReportFrameCompletedClosure () {}
192 public:
193 MediaReportFrameCompletedClosure (Media *media, MediaCallback *callback, IMediaDemuxer *context, MediaFrame *frame);
194 virtual void Dispose ();
196 MediaFrame *GetFrame () { return frame; }
197 IMediaDemuxer *GetDemuxer () { return (IMediaDemuxer *) GetContext (); }
201 * MediaMarkerFoundClosure
203 class MediaMarkerFoundClosure : public MediaClosure {
204 private:
205 MediaMarker *marker;
207 protected:
208 virtual ~MediaMarkerFoundClosure () {}
210 public:
211 MediaMarkerFoundClosure (Media *media, MediaCallback *callback, MediaElement *context);
212 virtual void Dispose ();
214 MediaMarker *GetMarker () { return marker; }
215 void SetMarker (MediaMarker *marker);
219 * MediaSeekClosure
221 class MediaSeekClosure : public MediaClosure {
222 private:
223 guint64 pts;
225 protected:
226 virtual ~MediaSeekClosure () {}
228 public:
229 MediaSeekClosure (Media *media, MediaCallback *callback, IMediaDemuxer *context, guint64 pts);
231 IMediaDemuxer *GetDemuxer () { return (IMediaDemuxer *) GetContext (); }
232 guint64 GetPts () { return pts; }
236 * *Info classes used to register codecs, demuxers and converters.
239 class MediaInfo {
240 public:
241 MediaInfo *next; // Used internally by Media.
242 MediaInfo () : next (NULL) {}
243 virtual ~MediaInfo () {}
244 virtual const char *GetName () { return "Unknown"; }
247 class DecoderInfo : public MediaInfo {
248 public:
249 virtual bool Supports (const char *codec) = 0;
250 virtual IMediaDecoder *Create (Media *media, IMediaStream *stream) = 0;
252 virtual ~DecoderInfo () {}
255 class DemuxerInfo : public MediaInfo {
256 public:
257 // <buffer> points to the first <length> bytes of a file.
258 // <length> is guaranteed to be at least 16 bytes.
259 // Possible return values:
260 // - MEDIA_SUCCESS: the demuxer supports this source
261 // - MEDIA_FAIL: the demuxer does not support this source
262 // - 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.
263 virtual MediaResult Supports (IMediaSource *source) = 0;
264 virtual IMediaDemuxer *Create (Media *media, IMediaSource *source) = 0;
267 class ConverterInfo : public MediaInfo {
268 public:
269 virtual bool Supports (MoonPixelFormat input, MoonPixelFormat output) = 0;
270 virtual IImageConverter *Create (Media *media, VideoStream *stream) = 0;
274 * ProgressEventArgs
276 /* @Namespace=None */
277 class ProgressEventArgs : public EventArgs {
278 public:
279 double progress;
281 ProgressEventArgs (double progress)
283 this->progress = progress;
288 * MediaWork
291 class MediaWork : public List::Node {
292 public:
293 MediaClosure *closure;
294 MediaWork (MediaClosure *closure);
295 virtual ~MediaWork ();
299 * IMediaObject
301 class IMediaObject : public EventObject {
302 private:
303 Media *media;
304 Mutex media_mutex;
305 // Media event handling
306 // media needs to support event handling on all threads, and EventObject isn't thread-safe
307 class EventData : public List::Node {
308 public:
309 int event_id;
310 EventHandler handler;
311 EventObject *context;
312 bool invoke_on_main_thread;
313 EventData (int event_id, EventHandler handler, EventObject *context, bool invoke_on_main_thread);
314 virtual ~EventData ();
316 class EmitData : public List::Node {
317 public:
318 int event_id;
319 EventHandler handler;
320 EventObject *context;
321 EventArgs *args;
322 EmitData (int event_id, EventHandler handler, EventObject *context, EventArgs *args);
323 virtual ~EmitData ();
325 List *events; // list of event handlers
326 List *emit_on_main_thread; // list of emit calls to emit on main thread
327 Mutex event_mutex;
329 void EmitList (List *list);
330 void EmitListMain ();
331 static void EmitListCallback (EventObject *obj);
333 protected:
334 virtual ~IMediaObject () {}
336 public:
337 IMediaObject (Type::Kind kind, Media *media);
338 virtual void Dispose ();
340 /* @GenerateCBinding,GeneratePInvoke */
341 Media *GetMediaReffed ();
342 void SetMedia (Media *value);
344 void ReportErrorOccurred (ErrorEventArgs *args);
345 /* @GenerateCBinding */
346 void ReportErrorOccurred (const char *message);
347 void ReportErrorOccurred (MediaResult result);
349 // All the event methods are thread-safe
350 void AddSafeHandler (int event_id, EventHandler handler, EventObject *context, bool invoke_on_main_thread = true);
351 void RemoveSafeHandlers (EventObject *context);
352 void EmitSafe (int event_id, EventArgs *args = NULL);
355 /* @Namespace=None,ManagedEvents=Manual */
356 class IMediaStream : public IMediaObject {
357 private:
358 void *context;
359 bool selected;
360 bool input_ended; // end of stream reached in demuxer
361 bool output_ended; // end of stream reached in decoder
362 guint64 first_pts; // The first pts in the stream, initialized to G_MAXUINT64
363 guint64 last_popped_pts; // The pts of the last frame returned, initialized to G_MAXUINT64
364 guint64 last_enqueued_pts; // The pts of the last frame enqueued, initialized to G_MAXUINT64
365 guint64 last_available_pts; // The last pts available, initialized to 0. Note that this field won't be correct for streams which CanSeekToPts.
366 Queue queue; // Our queue of demuxed frames
367 IMediaDecoder *decoder;
369 protected:
370 virtual ~IMediaStream () {}
371 virtual void FrameEnqueued () {}
373 static char *CreateCodec (int codec_id); // converts fourcc int value into a string
374 public:
375 class StreamNode : public List::Node {
376 private:
377 MediaFrame *frame;
378 public:
379 StreamNode (MediaFrame *frame);
380 virtual ~StreamNode ();
381 MediaFrame *GetFrame () { return frame; }
384 IMediaStream (Type::Kind kind, Media *media);
385 virtual void Dispose ();
387 // Video, Audio, Markers, etc.
388 virtual MediaStreamType GetType () = 0; // TODO: This should be removed, it clashes with GetType in EventObject.
389 /* @GenerateCBinding */
390 virtual MediaStreamType GetStreamType () { return GetType (); }
391 const char *GetStreamTypeName ();
393 IMediaDecoder *GetDecoder ();
394 void SetDecoder (IMediaDecoder *value);
396 /* @GenerateCBinding */
397 const char *GetCodec () { return codec; }
399 // User defined context value.
400 void *GetContext () { return context; }
401 void SetContext (void *context) { this->context = context; }
403 bool GetSelected () { return selected; }
404 void SetSelected (bool value);
406 void *extra_data;
407 int extra_data_size;
408 int codec_id;
409 guint64 duration; // 100-nanosecond units (pts)
410 char *codec; // freed upon destruction
411 // The minimum amount of padding any other part of the pipeline needs for frames from this stream.
412 // Used by the demuxer when reading frames, ensures that there are at least min_padding extra bytes
413 // at the end of the frame data (all initialized to 0).
414 int min_padding;
415 // 0-based index of the stream in the media
416 // set by the demuxer, until then its value must be -1
417 int index;
419 void EnqueueFrame (MediaFrame *frame);
420 MediaFrame *PopFrame ();
421 bool IsQueueEmpty ();
422 bool IsInQueue (MediaFrame *frame);
423 void ClearQueue ();
424 guint64 GetFirstPts () { return first_pts; }
425 guint64 GetLastPoppedPts () { return last_popped_pts; }
426 guint64 GetLastEnqueuedPts () { return last_enqueued_pts; }
427 void SetLastAvailablePts (guint64 value) { last_available_pts = MAX (value, last_available_pts); }
428 guint64 GetLastAvailablePts () { return last_available_pts; }
429 guint64 GetBufferedSize (); // Returns the time between the last frame returned and the last frame available (buffer time)
431 /* @GenerateCBinding */
432 int GetExtraDataSize () { return extra_data_size; }
433 /* @GenerateCBinding */
434 void SetExtraDataSize (int value) { extra_data_size = value; }
435 /* @GenerateCBinding */
436 void *GetExtraData () { return extra_data; }
437 /* @GenerateCBinding */
438 void SetExtraData (void *value) { extra_data = value; }
439 /* @GenerateCBinding */
440 int GetCodecId () { return codec_id; }
441 /* @GenerateCBinding */
442 void SetCodecId (int value) { codec_id = value; }
443 /* @GenerateCBinding */
444 guint64 GetDuration () { return duration; }
445 /* @GenerateCBinding */
446 void SetDuration (guint64 value) { duration = value; }
448 bool GetInputEnded ();
449 void SetInputEnded (bool value);
450 bool GetOutputEnded ();
451 void SetOutputEnded (bool value);
453 IMediaDemuxer *GetDemuxerReffed ();
455 void ReportSeekCompleted ();
456 #if DEBUG
457 void PrintBufferInformation ();
458 #endif
459 const static int FirstFrameEnqueuedEvent;
463 * Media
465 /* @Namespace=None,ManagedEvents=Manual */
466 class Media : public IMediaObject {
467 private:
468 static ConverterInfo *registered_converters;
469 static DemuxerInfo *registered_demuxers;
470 static DecoderInfo *registered_decoders;
471 static bool registering_ms_codecs;
472 static bool registered_ms_codecs;
474 Mutex mutex;
476 guint64 buffering_time; // Access must be protected with mutex.
477 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.
478 char *uri;
479 char *file;
480 IMediaSource *source;
481 IMediaDemuxer *demuxer;
482 List *markers;
483 bool initialized;
484 bool opened;
485 bool opening;
486 bool stopped;
487 bool error_reported; // If an error has been reported.
488 bool buffering_enabled;
489 bool in_open_internal; // detect recursive calls to OpenInternal
490 bool http_retried;
491 double download_progress;
492 double buffering_progress;
494 PlaylistRoot *playlist;
496 // Determines the container type and selects a demuxer. We have support for mp3 and asf demuxers.
497 // Also opens the demuxer.
498 // This method is supposed to be called multiple times, until either 'error_reported' is true or this method
499 // returns true. It will pick up wherever it left working last time.
500 bool SelectDemuxerAsync ();
502 // Selects decoders according to stream info.
503 // - Default is to use any MS decoder if available (and applicable), otherwise ffmpeg.
504 // Overridable by MOONLIGHT_OVERRIDES, set ms-codecs=no to disable ms codecs, and ffmpeg-codecs=no to disable ffempg codecs
505 // This method is supposed to be called multiple times, until either 'error_reported' is true or this method
506 // returns true. It will pick up wherever it left working last time.
507 bool SelectDecodersAsync ();
509 // This method is supposed to be called multiple times, until the media has been successfully opened or an error occurred.
510 void OpenInternal ();
511 static MediaResult OpenInternal (MediaClosure *closure);
512 static MediaResult DisposeObjectInternal (MediaClosure *closure);
514 static MediaResult StopCallback (MediaClosure *closure);
515 static MediaResult PauseCallback (MediaClosure *closure);
516 static MediaResult PlayCallback (MediaClosure *closure);
517 void Stop ();
518 void Pause ();
519 void Play ();
521 protected:
522 virtual ~Media ();
524 public:
525 Media (PlaylistRoot *root);
527 virtual void Dispose ();
529 static bool InMediaThread ();
530 bool EnqueueWork (MediaClosure *closure, bool wakeup = true);
532 // Calls obj->Dispose on the media thread.
533 void DisposeObject (EventObject *obj);
535 // Initialize the Media.
536 // These methods may raise MediaError events.
537 void Initialize (Downloader *downloader, const char *PartName); // MediaElement.SetSource (dl, 'PartName');
538 void Initialize (const char *uri); // MediaElement.Source = 'uri';
539 void Initialize (IMediaDemuxer *demuxer); // MediaElement.SetSource (demuxer);
540 void Initialize (IMediaSource *source);
542 // Start opening the media.
543 // When done, OpenCompleted event is raised.
544 // In case of failure, MediaError event is raised
545 void OpenAsync ();
547 void ReportOpenDemuxerCompleted (); // This method is called by the demuxer when it has opened.
548 void ReportOpenDecoderCompleted (IMediaDecoder *decoder); // This method is called by any of the decoders when it has opened.
549 void ReportOpenCompleted (); // Raise the OpenCompleted event.
551 void ReportDownloadProgress (double progress);
552 void ReportBufferingProgress (double progress);
554 // Media playback
555 void PlayAsync (); // Raises CurrentStateChanged
556 void PauseAsync (); // Raises CurrentStateChanged
557 void StopAsync (); // Raises CurrentStateChanged
558 // Seek to the specified pts
559 // When done, SeekCompleted is raised
560 // In case of failure, MediaError is raised.
561 void SeekAsync (guint64 pts);
562 void ReportSeekCompleted (guint64 pts); // This method is called by IMediaDemuxer when a seek is completed. Raises the SeekCompleted event.
564 void ClearQueue (); // Clears the queue and make sure the thread has finished processing what it's doing
565 void WakeUp ();
567 void SetBufferingTime (guint64 buffering_time);
568 guint64 GetBufferingTime ();
570 void SetBufferingEnabled (bool value);
572 IMediaSource *GetSource () { return source; }
573 IMediaDemuxer *GetDemuxerReffed (); /* thread-safe */
574 const char *GetFile () { return file; }
575 const char *GetUri () { return uri; }
576 void SetFileOrUrl (const char *value);
578 static void Warning (MediaResult result, const char *format, ...);
579 // A list of MediaMarker::Node.
580 // This is the list of markers found in the metadata/headers (not as a separate stream).
581 // Will never return NULL.
582 List *GetMarkers ();
583 double GetDownloadProgress () { return download_progress; }
584 double GetBufferingProgress () { return buffering_progress; }
586 PlaylistRoot *GetPlaylistRoot ();
588 bool IsOpened () { return opened; }
589 bool IsOpening () { return opening; }
590 bool IsStopped () { return stopped; }
592 void RetryHttp (ErrorEventArgs *args);
594 void ReportErrorOccurred (ErrorEventArgs *args);
595 void ReportErrorOccurred (const char *message);
596 void ReportErrorOccurred (MediaResult result);
598 bool HasReportedError () { return error_reported; }
600 const static int OpeningEvent;
601 const static int OpenCompletedEvent;
602 const static int SeekingEvent;
603 const static int SeekCompletedEvent;
604 const static int CurrentStateChangedEvent;
605 const static int MediaErrorEvent;
606 const static int DownloadProgressChangedEvent;
607 const static int BufferingProgressChangedEvent;
609 // Registration functions
610 // This class takes ownership of the infos and will delete them (not free) when the Media is shutdown.
611 static void RegisterDemuxer (DemuxerInfo *info);
612 /* @GenerateCBinding */
613 static void RegisterDecoder (DecoderInfo *info);
614 static void RegisterConverter (ConverterInfo *info);
616 static void RegisterMSCodecs ();
617 static bool IsMSCodecsInstalled ();
619 static void Initialize ();
620 static void Shutdown ();
624 * MediaThreadPool
626 * The most important requirement for the thread pool is that it never executes several work items for a single Media instance simultaneously.
627 * 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
628 * a Media instance which is not in the list.
630 class MediaThreadPool {
631 private:
632 static pthread_mutex_t mutex;
633 static pthread_cond_t condition; /* signalled when work has been added */
634 static pthread_cond_t completed_condition; /* signalled when work has completed executing */
635 static const int max_threads = 4; /* max 4 threads for now */
636 static int count; // the number of created threads
637 static pthread_t threads [max_threads]; // array of threads
638 static bool valid [max_threads]; // specifies which thread indices are valid.
639 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.
640 static Deployment *deployments [max_threads]; // array of deployments currently being worked on.
641 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).
642 static List *queue;
644 static void *WorkerLoop (void *data);
646 public:
647 // Removes all enqueued work for the specified media.
648 static void RemoveWork (Media *media);
649 // Waits until all enqueued work for the specified deployment has finished
650 // executing and there is no more work for the specified deployment. Note that
651 // it does not touch the queue, it just waits for the threads to finish cleaning
652 // up the queue.
653 static void WaitForCompletion (Deployment *deployment); /* Main thread only */
654 static void AddWork (MediaClosure *closure, bool wakeup);
655 static void WakeUp ();
656 static void Initialize ();
657 static void Shutdown ();
659 // this method checks if the current thread is a thread-pool thread
660 static bool IsThreadPoolThread ();
663 class MediaFrame : public EventObject {
664 private:
665 void Initialize ();
667 protected:
668 virtual ~MediaFrame ();
670 public:
671 MediaFrame (IMediaStream *stream);
672 /* @GenerateCBinding,GeneratePInvoke */
673 MediaFrame (IMediaStream *stream, guint8 *buffer, guint32 buflen, guint64 pts, bool keyframe);
674 void Dispose ();
676 /* @GenerateCBinding */
677 void AddState (MediaFrameState state) { this->state |= (guint16) state; } // There's no way of "going back" to an earlier state
678 bool IsDecoded () { return (((MediaFrameState) state) & MediaFrameDecoded) == MediaFrameDecoded; }
679 bool IsDemuxed () { return (((MediaFrameState) state) & MediaFrameDemuxed) == MediaFrameDemuxed; }
680 bool IsConverted () { return (((MediaFrameState) state) & MediaFrameConverted) == MediaFrameConverted; }
681 bool IsPlanar () { return (((MediaFrameState) state) & MediaFramePlanar) == MediaFramePlanar; }
682 /* @GenerateCBinding */
683 bool IsKeyFrame () { return (((MediaFrameState) state) & MediaFrameKeyFrame) == MediaFrameKeyFrame; }
684 bool IsMarker () { return (((MediaFrameState) state) & MediaFrameMarker) == MediaFrameMarker; }
686 IMediaStream *stream;
687 MediaMarker *marker;
688 void *decoder_specific_data; // data specific to the decoder
689 guint64 pts; // Set by the demuxer
690 guint64 duration; // Set by the demuxer
692 guint16 state; // Current state of the frame
693 guint16 event; // special frame event if non-0
695 // The demuxer sets these to the encoded data which the
696 // decoder then uses and replaces with the decoded data.
697 guint8 *buffer;
698 guint32 buflen;
700 // planar data
701 guint8 *data_stride[4]; // Set by the decoder
702 int srcSlideY; // Set by the decoder
703 int srcSlideH; // Set by the decoder
704 int srcStride[4]; // Set by the decoder
706 // The decoded size of the frame (might be bigger or smaller than the size of the stream).
707 // 0 = the size specified in the stream
708 gint32 width;
709 gint32 height;
711 /* @GenerateCBinding */
712 guint32 GetBufLen () { return buflen; }
713 /* @GenerateCBinding */
714 void SetBufLen (guint32 value) { buflen = value; }
715 /* @GenerateCBinding */
716 guint8* GetBuffer () { return buffer; }
717 /* @GenerateCBinding */
718 void SetBuffer (guint8 *value) { buffer = value; }
719 /* @GenerateCBinding */
720 guint64 GetPts () { return pts; }
721 /* @GenerateCBinding */
722 void SetPts (guint64 value) { pts = value; }
724 /* @GenerateCBinding */
725 gint32 GetWidth () { return width; }
726 /* @GenerateCBinding */
727 void SetWidth (gint32 value) { width = value; }
728 /* @GenerateCBinding */
729 gint32 GetHeight () { return height; }
730 /* @GenerateCBinding */
731 void SetHeight (gint32 value) { height = value; }
732 /* @GenerateCBinding */
733 void SetDataStride (guint8 *a, guint8 *b, guint8 *c, guint8 *d);
734 /* @GenerateCBinding */
735 void SetSrcStride (int a, int b, int c, int d);
736 /* @GenerateCBinding */
737 void SetSrcSlideY (int value);
738 /* @GenerateCBinding */
739 void SetSrcSlideH (int value);
740 /* @GenerateCBinding */
741 void SetDecoderSpecificData (void *value) { decoder_specific_data = value; }
746 class MediaMarker : public EventObject {
747 guint64 pts; // 100-nanosecond units (pts)
748 char *type;
749 char *text;
751 protected:
752 virtual ~MediaMarker ();
754 public:
755 class Node : public List::Node {
756 public:
757 Node (MediaMarker *m)
759 marker = m;
760 marker->ref ();
763 virtual ~Node ()
765 marker->unref ();
768 MediaMarker *marker;
771 MediaMarker (const char *type, const char *text, guint64 pts);
773 const char *Type () { return type; }
774 const char *Text () { return text; }
775 guint64 Pts () { return pts; }
778 // Interfaces
780 class IMediaDemuxer : public IMediaObject {
781 private:
782 class PtsNode : public List::Node {
783 public:
784 guint64 pts;
785 PtsNode (guint64 pts)
787 this->pts = pts;
790 IMediaStream **streams;
791 int stream_count;
792 bool opened;
793 bool opening;
794 bool seeking; /* Only media thread may access, no lock required. When set, the demuxer should not request new frames */
796 * Set on main thread, read/reset on media thread: access needs mutex locked.
797 * When a seek is pending, indicates the position we should seek to. We specifically
798 * do not enqueue the pts with the seek request - this would cause
799 * multiple seeks with unpredictable ordeing when SeekAsync is called again before the
800 * first seek has finished
802 List seeks; /* The FIFO list of seeked-to pts. All threads may use, locking required. */
803 IMediaStream *pending_stream; // the stream we're waiting for a frame for. media thread only.
804 bool pending_fill_buffers;
805 Mutex mutex;
807 * We only want frames after the last keyframe before the pts we seeked to.
808 * Store the seeked-to pts here, so that the IMediaStream can drop frames it
809 * doesn't need.
811 guint64 seeked_to_pts;
813 static MediaResult ReportSeekCompletedCallback (MediaClosure *closure);
814 static MediaResult ReportGetFrameCompletedCallback (MediaClosure *closure);
815 static MediaResult GetFrameCallback (MediaClosure *closure);
816 static MediaResult FillBuffersCallback (MediaClosure *closure);
817 static MediaResult OpenCallback (MediaClosure *closure);
818 static MediaResult SeekCallback (MediaClosure *closure);
820 void FillBuffersInternal ();
822 protected:
823 IMediaSource *source;
825 IMediaDemuxer (Type::Kind kind, Media *media, IMediaSource *source);
826 IMediaDemuxer (Type::Kind kind, Media *media);
828 virtual ~IMediaDemuxer () {}
830 void SetStreams (IMediaStream **streams, int count);
831 gint32 AddStream (IMediaStream *stream);
833 virtual void CloseDemuxerInternal () {};
834 virtual void GetDiagnosticAsyncInternal (MediaStreamSourceDiagnosticKind diagnosticKind) {}
835 virtual void GetFrameAsyncInternal (IMediaStream *stream) = 0;
836 virtual void OpenDemuxerAsyncInternal () = 0;
837 virtual void SeekAsyncInternal (guint64 pts) = 0;
838 virtual void SwitchMediaStreamAsyncInternal (IMediaStream *stream) = 0;
840 void EnqueueOpen ();
841 void EnqueueReportSeekCompleted (guint64 pts);
842 void EnqueueGetFrame (IMediaStream *stream);
843 void EnqueueReportGetFrameCompleted (MediaFrame *frame);
844 /* Re-enqueue the seek. */
845 void EnqueueSeek ();
846 void SeekAsync ();
848 public:
849 virtual void Dispose ();
851 void CloseDemuxer () {};
852 void GetDiagnosticAsync (MediaStreamSourceDiagnosticKind diagnosticKind) {}
853 void GetFrameAsync (IMediaStream *stream);
854 void OpenDemuxerAsync ();
855 /* Might not seek immediately, It will wait until there are no pending frames. */
856 void SeekAsync (guint64 pts);
857 void SwitchMediaStreamAsync (IMediaStream *stream);
859 /* @GenerateCBinding,GeneratePInvoke */
860 void ReportOpenDemuxerCompleted ();
861 /* @GenerateCBinding,GeneratePInvoke */
862 void ReportGetFrameCompleted (MediaFrame *frame);
863 /* @GenerateCBinding,GeneratePInvoke */
864 void ReportGetFrameProgress (double bufferingProgress);
865 /* @GenerateCBinding,GeneratePInvoke */
866 void ReportSeekCompleted (guint64 pts);
867 /* @GenerateCBinding,GeneratePInvoke */
868 void ReportSwitchMediaStreamCompleted (IMediaStream *stream);
869 /* @GenerateCBinding,GeneratePInvoke */
870 void ReportGetDiagnosticCompleted (MediaStreamSourceDiagnosticKind diagnosticKind, gint64 diagnosticValue);
872 guint64 GetBufferedSize ();
873 void FillBuffers ();
874 void ClearBuffers ();
876 void PrintBufferInformation ();
877 guint64 GetSeekedToPts () { return seeked_to_pts; }
879 int GetStreamCount () { return stream_count; }
880 IMediaStream *GetStream (int index);
881 // Gets the longest duration from all the streams
882 virtual guint64 GetDuration (); // 100-nanosecond units (pts)
883 virtual const char *GetName () = 0;
884 virtual void UpdateSelected (IMediaStream *stream) {};
886 guint64 GetLastAvailablePts ();
887 IMediaSource *GetSource () { return source; }
888 bool IsOpened () { return opened; }
889 bool IsOpening () { return opening; }
891 virtual bool GetCanSeek () { return true; }
892 virtual bool IsPlaylist () { return false; }
893 virtual Playlist *GetPlaylist () { return NULL; }
896 class IMediaDecoder : public IMediaObject {
897 private:
898 bool opening;
899 bool opened;
900 bool input_ended;
901 MoonPixelFormat pixel_format; // The pixel format this codec outputs. Open () should fill this in.
902 IMediaStream *stream;
903 Queue queue; // the list of frames to decode.
905 static MediaResult DecodeFrameCallback (MediaClosure *closure);
907 class FrameNode : public List::Node {
908 public:
909 MediaFrame *frame;
911 FrameNode (MediaFrame *f) : frame (f)
913 frame->ref ();
916 virtual ~FrameNode ()
918 frame->unref ();
922 protected:
923 virtual ~IMediaDecoder () {}
926 * Called when a frame needs to get decoded. The implementation needs to call
927 * ReportDecodeFrameCompleted at least once for each DecodeFrameAsync request
928 * (calling ReportDecodeFrameCompleted more than once for each DecodeFrameAsync
929 * request is allowed). The implementation may call ReportDecodeFrameCompleted
930 * with a null buffer (for instance if it does not have enough input to produce output).
932 virtual void DecodeFrameAsyncInternal (MediaFrame *frame) = 0;
933 virtual void OpenDecoderAsyncInternal () = 0;
935 // InputEnded is called when there is no more input. If the codec has delayed frames,
936 // it must call ReportDecodeFrameCompleted with those frames (all of them).
937 virtual void InputEnded () { };
939 public:
940 IMediaDecoder (Type::Kind kind, Media *media, IMediaStream *stream);
941 virtual void Dispose ();
943 // If MediaFrame->decoder_specific_data is non-NULL, this method is called in ~MediaFrame.
944 virtual void Cleanup (MediaFrame *frame) {}
945 virtual void CleanState () {}
946 virtual bool HasDelayedFrame () { return false; }
948 virtual const char *GetName () { return GetTypeName (); }
950 // This method is called when the demuxer has finished seeking.
951 void ReportSeekCompleted ();
952 // This method is called when the demuxer is out of data.
953 void ReportInputEnded ();
954 /* @GenerateCBinding */
955 void ReportDecodeFrameCompleted (MediaFrame *frame);
956 /* @GenerateCBinding */
957 void ReportOpenDecoderCompleted ();
958 /* @GenerateCBinding */
959 void SetPixelFormat (MoonPixelFormat value) { pixel_format = value; }
961 void DecodeFrameAsync (MediaFrame *frame, bool enqueue_always);
962 void OpenDecoderAsync ();
964 bool IsOpening () { return opening; }
965 bool IsOpened () { return opened; }
966 MoonPixelFormat GetPixelFormat () { return pixel_format; }
967 IMediaStream *GetStream () { return stream; }
969 bool IsDecoderQueueEmpty () { return queue.IsEmpty (); }
974 * Inherit from this class to provide image converters (yuv->rgb for instance)
976 class IImageConverter : public IMediaObject {
977 protected:
978 virtual ~IImageConverter () {}
980 public:
981 MoonPixelFormat output_format;
982 MoonPixelFormat input_format;
983 VideoStream *stream;
985 IImageConverter (Type::Kind kind, Media *media, VideoStream *stream);
987 virtual MediaResult Open () = 0;
988 virtual MediaResult Convert (guint8 *src[], int srcStride[], int srcSlideY, int srcSlideH, guint8 *dest[], int dstStride []) = 0;
992 * IMediaSource
994 class IMediaSource : public IMediaObject {
995 private:
996 // General locking behaviour:
997 // All protected virtual methods must be called with the mutex
998 // locked. If a derived virtual method needs to lock, it needs
999 // to be implemented as a protected virtual method xxxInternal
1000 // which requires the mutex to be locked, and then a public
1001 // method in IMediaSource which does the locking. No public method
1002 // in IMediaSource may be called from the xxxInternal methods.
1003 pthread_mutex_t mutex;
1004 pthread_cond_t condition;
1006 protected:
1007 virtual ~IMediaSource ();
1009 void Lock ();
1010 void Unlock ();
1012 // All these methods must/will be called with the lock locked.
1013 virtual gint32 ReadInternal (void *buf, guint32 n);
1014 virtual gint32 PeekInternal (void *buf, guint32 n);
1015 virtual bool SeekInternal (gint64 offset, int mode);
1016 virtual gint64 GetLastAvailablePositionInternal () { return -1; }
1017 virtual gint64 GetPositionInternal ();
1018 virtual gint64 GetSizeInternal ();
1020 public:
1021 IMediaSource (Type::Kind kind, Media *media);
1022 virtual void Dispose ();
1024 // Initializes this stream (and if it succeeds, it can be read from later on).
1025 // streams based on remote content (live/progress) should contact the server
1026 // and try to start downloading content
1027 // file streams should try to open the file
1028 virtual MediaResult Initialize () = 0;
1029 virtual MediaSourceType GetType () = 0;
1031 // Reads 'n' bytes into 'buf'. If data isn't available it will
1032 // read the amount of data available. Returns the number of bytes read.
1033 // This method will lock the mutex.
1034 gint32 ReadSome (void *buf, guint32 n);
1036 // Reads 'n' bytes into 'buf'.
1037 // Returns false if 'n' bytes couldn't be read.
1038 // This method will lock the mutex.
1039 bool ReadAll (void *buf, guint32 n);
1041 // Reads 'n' bytes into 'buf', starting at position 'start'. If 'start' is -1,
1042 // then start at the current position. If data isn't available it will
1043 // read the amount of data available. Returns false if 'n' bytes couldn't be
1044 // read.
1045 // This method will lock the mutex.
1046 bool Peek (void *buf, guint32 n);
1048 virtual bool CanSeek () { return true; }
1050 // Seeks to the specified 'offset', using the specified 'mode'.
1051 // This method will lock the mutex.
1052 bool Seek (gint64 offset, int mode = SEEK_CUR);
1054 // Seeks to the specified 'pts'.
1055 virtual bool CanSeekToPts () { return false; }
1056 virtual MediaResult SeekToPts (guint64 pts) { return MEDIA_FAIL; }
1058 // Returns the current reading position
1059 // This method will lock the mutex.
1060 gint64 GetPosition ();
1062 // Returns the size of the source. This method may return -1 if the
1063 // size isn't known.
1064 // This method will lock the mutex.
1065 gint64 GetSize ();
1067 virtual bool Eof () = 0;
1069 // Returns the last available position
1070 // If the returned value is -1, then everything is available.
1071 // This method will lock the mutex.
1072 gint64 GetLastAvailablePosition ();
1074 // Checks if the specified position can be read
1075 // upon return, and if the position is not availble eof determines whether the position is not available because
1076 // the file isn't that big (eof = true), or the position hasn't been read yet (eof = false).
1077 // if the position is available, eof = false
1078 bool IsPositionAvailable (gint64 position, bool *eof);
1080 // If the derived class knows which demuxer it needs,
1081 // it should override this method and return a new demuxer.
1082 virtual IMediaDemuxer *CreateDemuxer (Media *media) { return NULL; }
1084 virtual const char *ToString () { return "IMediaSource"; }
1087 class ManagedStreamSource : public IMediaSource {
1088 private:
1089 ManagedStreamCallbacks stream;
1091 protected:
1092 virtual ~ManagedStreamSource ();
1094 virtual gint32 ReadInternal (void *buf, guint32 n);
1095 virtual gint32 PeekInternal (void *buf, guint32 n);
1096 virtual bool SeekInternal (gint64 offset, int mode);
1097 virtual gint64 GetPositionInternal ();
1098 virtual gint64 GetSizeInternal ();
1100 public:
1101 ManagedStreamSource (Media *media, ManagedStreamCallbacks *stream);
1103 virtual MediaResult Initialize () { return MEDIA_SUCCESS; }
1104 virtual MediaSourceType GetType () { return MediaSourceTypeManagedStream; }
1106 virtual bool Eof () { return GetPositionInternal () == GetSizeInternal (); }
1108 virtual const char *ToString () { return GetTypeName (); }
1111 class FileSource : public IMediaSource {
1112 public: // private:
1113 gint64 size;
1114 FILE *fd;
1115 bool temp_file;
1116 char buffer [1024];
1118 void UpdateSize ();
1119 protected:
1120 char *filename;
1122 virtual ~FileSource ();
1123 FileSource (Type::Kind object_kind, Media *media, bool temp_file);
1125 MediaResult Open (const char *filename);
1127 virtual gint32 ReadInternal (void *buf, guint32 n);
1128 virtual gint32 PeekInternal (void *buf, guint32 n);
1129 virtual bool SeekInternal (gint64 offset, int mode);
1130 virtual gint64 GetPositionInternal ();
1131 virtual gint64 GetSizeInternal ();
1133 public:
1134 FileSource (Media *media, const char *filename);
1135 virtual void Dispose ();
1137 virtual MediaResult Initialize ();
1138 virtual MediaSourceType GetType () { return MediaSourceTypeFile; }
1140 virtual bool Eof ();
1142 virtual const char *ToString () { return filename; }
1144 const char *GetFileName () { return filename; }
1147 class ProgressiveSource : public FileSource {
1148 private:
1149 gint64 write_pos;
1150 gint64 size;
1151 // To avoid locking while reading and writing (since reading is done on
1152 // the media thread and writing on the main thread), we open two file
1153 // handlers, one for reading (in FileSource) and the other one here
1154 // for writing.
1155 FILE *write_fd;
1156 char *uri;
1157 Cancellable *cancellable;
1159 virtual gint64 GetLastAvailablePositionInternal () { return size == write_pos ? write_pos : write_pos & ~(1024*4-1); }
1160 virtual gint64 GetSizeInternal () { return size; }
1162 static void data_write (void *data, gint32 offset, gint32 n, void *closure);
1163 static void notify_func (NotifyType type, gint64 args, void *closure);
1164 static void delete_cancellable (EventObject *data);
1166 void Notify (NotifyType, gint64 args);
1168 void DownloadComplete ();
1169 void DownloadFailed ();
1170 void DataWrite (void *data, gint32 offset, gint32 n);
1171 void NotifySize (gint64 size);
1172 void SetTotalSize (gint64 size);
1174 void CloseWriteFile ();
1176 protected:
1177 virtual ~ProgressiveSource ();
1179 public:
1180 ProgressiveSource (Media *media, const char *uri);
1181 virtual void Dispose ();
1183 virtual MediaResult Initialize ();
1184 virtual MediaSourceType GetType () { return MediaSourceTypeProgressive; }
1188 * MemorySource
1190 class MemorySource : public IMediaSource {
1191 private:
1192 void *memory;
1193 gint32 size;
1194 gint64 start;
1195 gint64 pos;
1196 bool owner;
1198 protected:
1199 virtual ~MemorySource ();
1201 virtual gint32 ReadInternal (void *buf, guint32 n);
1202 virtual gint32 PeekInternal (void *buf, guint32 n);
1203 virtual bool SeekInternal (gint64 offset, int mode);
1204 virtual gint64 GetSizeInternal () { return size; }
1205 virtual gint64 GetPositionInternal () { return pos + start; }
1206 virtual gint64 GetLastAvailablePositionInternal () { return start + size; }
1208 public:
1209 MemorySource (Media *media, void *memory, gint32 size, gint64 start = 0, bool owner = true);
1211 void *GetMemory () { return memory; }
1212 void Release (void) { delete this; }
1214 void SetOwner (bool value) { owner = value; }
1215 gint64 GetStart () { return start; }
1217 virtual MediaResult Initialize () { return MEDIA_SUCCESS; }
1218 virtual MediaSourceType GetType () { return MediaSourceTypeMemory; }
1220 virtual bool CanSeek () { return true; }
1221 virtual bool Eof () { return pos >= size; }
1223 virtual const char *ToString () { return "MemorySource"; }
1226 class VideoStream : public IMediaStream {
1227 protected:
1228 virtual ~VideoStream ();
1230 public:
1231 void Dispose ();
1233 IImageConverter *converter; // This stream has the ownership of the converter, it will be deleted upon destruction.
1234 guint32 bits_per_sample;
1235 guint64 pts_per_frame; // Duration (in pts) of each frame. Set to 0 if unknown.
1236 guint64 initial_pts;
1237 guint32 height;
1238 guint32 width;
1239 guint32 bit_rate;
1241 VideoStream (Media *media);
1243 /* @GenerateCBinding,GeneratePInvoke */
1244 VideoStream (Media *media, int codec_id, guint32 width, guint32 height, guint64 duration, gpointer extra_data, guint32 extra_data_size);
1246 virtual MediaStreamType GetType () { return MediaTypeVideo; }
1248 guint32 GetBitsPerSample () { return bits_per_sample; }
1249 guint32 GetPtsPerFrame () { return pts_per_frame; }
1250 guint32 GetInitialPts () { return initial_pts; }
1251 /* @GenerateCBinding */
1252 guint32 GetWidth () { return width; }
1253 /* @GenerateCBinding */
1254 guint32 GetHeight () { return height; }
1255 guint32 GetBitRate () { return bit_rate; }
1258 class AudioStream : public IMediaStream {
1259 private:
1260 /* input format */
1261 int input_bits_per_sample;
1262 int input_block_align;
1263 int input_sample_rate;
1264 int input_channels;
1265 int input_bit_rate;
1267 /* output format */
1268 int output_bits_per_sample;
1269 int output_block_align;
1270 int output_sample_rate;
1271 int output_channels;
1272 int output_bit_rate;
1273 protected:
1274 virtual ~AudioStream () {}
1276 public:
1278 AudioStream (Media *media);
1280 /* @GenerateCBinding,GeneratePInvoke */
1281 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);
1283 virtual MediaStreamType GetType () { return MediaTypeAudio; }
1285 // TODO: remove the non Input/Output accessors
1286 // wait until later since it is a two-way codec abi breakage.
1288 /* @GenerateCBinding */
1289 int GetBitsPerSample () { return input_bits_per_sample; }
1290 /* @GenerateCBinding */
1291 void SetBitsPerSample (int value) { output_bits_per_sample = input_bits_per_sample = value; }
1292 /* @GenerateCBinding */
1293 int GetBlockAlign () { return input_block_align; }
1294 /* @GenerateCBinding */
1295 void SetBlockAlign (int value) { output_block_align = input_block_align = value; }
1296 /* @GenerateCBinding */
1297 int GetSampleRate () { return input_sample_rate; }
1298 /* @GenerateCBinding */
1299 void SetSampleRate (int value) { output_sample_rate = input_sample_rate = value; }
1300 /* @GenerateCBinding */
1301 int GetChannels () { return input_channels; }
1302 /* @GenerateCBinding */
1303 void SetChannels (int value) { output_channels = input_channels = value; }
1304 /* @GenerateCBinding */
1305 int GetBitRate () { return input_bit_rate; }
1306 /* @GenerateCBinding */
1307 void SetBitRate (int value) { output_bit_rate = input_bit_rate = value; }
1309 // input accessors
1311 /* @GenerateCBinding */
1312 int GetInputBitsPerSample () { return input_bits_per_sample; }
1313 /* @GenerateCBinding */
1314 void SetInputBitsPerSample (int value) { input_bits_per_sample = value; }
1316 /* @GenerateCBinding */
1317 int GetInputBlockAlign () { return input_block_align; }
1318 /* @GenerateCBinding */
1319 void SetInputBlockAlign (int value) { input_block_align = value; }
1321 /* @GenerateCBinding */
1322 int GetInputSampleRate () { return input_sample_rate; }
1323 /* @GenerateCBinding */
1324 void SetInputSampleRate (int value) { input_sample_rate = value; }
1326 /* @GenerateCBinding */
1327 int GetInputChannels () { return input_channels; }
1328 /* @GenerateCBinding */
1329 void SetInputChannels (int value) { input_channels = value; }
1331 /* @GenerateCBinding */
1332 int GetInputBitRate () { return input_bit_rate; }
1333 /* @GenerateCBinding */
1334 void SetInputBitRate (int value) { input_bit_rate = value; }
1336 // output accessors
1338 /* @GenerateCBinding */
1339 int GetOutputBitsPerSample () { return output_bits_per_sample; }
1340 /* @GenerateCBinding */
1341 void SetOutputBitsPerSample (int value) { output_bits_per_sample = value; }
1343 /* @GenerateCBinding */
1344 int GetOutputBlockAlign () { return output_block_align; }
1345 /* @GenerateCBinding */
1346 void SetOutputBlockAlign (int value) { output_block_align = value; }
1348 /* @GenerateCBinding */
1349 int GetOutputSampleRate () { return output_sample_rate; }
1350 /* @GenerateCBinding */
1351 void SetOutputSampleRate (int value) { output_sample_rate = value; }
1353 /* @GenerateCBinding */
1354 int GetOutputChannels () { return output_channels; }
1355 /* @GenerateCBinding */
1356 void SetOutputChannels (int value) { output_channels = value; }
1358 /* @GenerateCBinding */
1359 int GetOutputBitRate () { return output_bit_rate; }
1360 /* @GenerateCBinding */
1361 void SetOutputBitRate (int value) { output_bit_rate = value; }
1365 * ExternalDemuxer
1368 /* @CBindingRequisite */
1369 typedef void (* CloseDemuxerCallback) (void *instance);
1370 /* @CBindingRequisite */
1371 typedef void (* GetDiagnosticAsyncCallback) (void *instance, int /*MediaStreamSourceDiagnosticKind*/ diagnosticKind);
1372 /* @CBindingRequisite */
1373 typedef void (* GetFrameAsyncCallback) (void *instance, int /*MediaStreamType*/ mediaStreamType);
1374 /* @CBindingRequisite */
1375 typedef void (* OpenDemuxerAsyncCallback) (void *instance, IMediaDemuxer *demuxer);
1376 /* @CBindingRequisite */
1377 typedef void (* SeekAsyncCallback) (void *instance, guint64 seekToTime);
1378 /* @CBindingRequisite */
1379 typedef void (* SwitchMediaStreamAsyncCallback) (void *instance, IMediaStream *mediaStreamDescription);
1381 class ExternalDemuxer : public IMediaDemuxer {
1382 private:
1383 void *instance;
1384 bool can_seek;
1385 pthread_rwlock_t rwlock;
1386 CloseDemuxerCallback close_demuxer_callback;
1387 GetDiagnosticAsyncCallback get_diagnostic_async_callback;
1388 GetFrameAsyncCallback get_sample_async_callback;
1389 OpenDemuxerAsyncCallback open_demuxer_async_callback;
1390 SeekAsyncCallback seek_async_callback;
1391 SwitchMediaStreamAsyncCallback switch_media_stream_async_callback;
1393 protected:
1394 virtual ~ExternalDemuxer ();
1396 virtual void CloseDemuxerInternal ();
1397 virtual void GetDiagnosticAsyncInternal (MediaStreamSourceDiagnosticKind diagnosticsKind);
1398 virtual void GetFrameAsyncInternal (IMediaStream *stream);
1399 virtual void OpenDemuxerAsyncInternal ();
1400 virtual void SeekAsyncInternal (guint64 seekToTime);
1401 virtual void SwitchMediaStreamAsyncInternal (IMediaStream *mediaStreamDescription);
1403 public:
1404 ExternalDemuxer (Media *media, void *instance, CloseDemuxerCallback close_demuxer,
1405 GetDiagnosticAsyncCallback get_diagnostic, GetFrameAsyncCallback get_sample, OpenDemuxerAsyncCallback open_demuxer,
1406 SeekAsyncCallback seek, SwitchMediaStreamAsyncCallback switch_media_stream);
1408 virtual void Dispose ();
1410 /* @GenerateCBinding,GeneratePInvoke */
1411 void SetCanSeek (bool value);
1413 /* @GenerateCBinding,GeneratePInvoke */
1414 void ClearCallbacks (); /* thread-safe */
1416 /* @GenerateCBinding,GeneratePInvoke */
1417 gint32 AddStream (IMediaStream *stream);
1419 virtual bool GetCanSeek () { return can_seek; }
1421 virtual const char *GetName () { return "ExternalDemuxer"; }
1425 * ExternalDecoder
1428 /* @CBindingRequisite */
1429 typedef void (* ExternalDecoder_DecodeFrameAsyncCallback) (void *instance, MediaFrame *frame);
1430 /* @CBindingRequisite */
1431 typedef void (* ExternalDecoder_OpenDecoderAsyncCallback) (void *instance);
1432 /* @CBindingRequisite */
1433 typedef void (* ExternalDecoder_CleanupCallback) (void *instance, MediaFrame *frame);
1434 /* @CBindingRequisite */
1435 typedef void (* ExternalDecoder_CleanStateCallback) (void *instance);
1436 /* @CBindingRequisite */
1437 typedef bool (* ExternalDecoder_HasDelayedFrameCallback) (void *instance);
1438 /* @CBindingRequisite */
1439 typedef void (* ExternalDecoder_DisposeCallback) (void *instance);
1440 /* @CBindingRequisite */
1441 typedef void (* ExternalDecoder_DtorCallback) (void *instance);
1443 class ExternalDecoder : public IMediaDecoder {
1444 private:
1445 void *instance;
1446 char *name;
1447 ExternalDecoder_DecodeFrameAsyncCallback decode_frame_async;
1448 ExternalDecoder_OpenDecoderAsyncCallback open_decoder_async;
1449 ExternalDecoder_CleanupCallback cleanup;
1450 ExternalDecoder_CleanStateCallback clean_state;
1451 ExternalDecoder_HasDelayedFrameCallback has_delayed_frame;
1452 ExternalDecoder_DisposeCallback dispose;
1453 ExternalDecoder_DtorCallback dtor;
1455 protected:
1456 virtual ~ExternalDecoder ();
1458 virtual void DecodeFrameAsyncInternal (MediaFrame *frame);
1459 virtual void OpenDecoderAsyncInternal ();
1461 virtual void InputEnded ();
1462 public:
1463 /* @GenerateCBinding */
1464 ExternalDecoder (Media *media, IMediaStream *stream, void *instance, const char *name,
1465 ExternalDecoder_DecodeFrameAsyncCallback decode_frame_async,
1466 ExternalDecoder_OpenDecoderAsyncCallback open_decoder_async,
1467 ExternalDecoder_CleanupCallback cleanup,
1468 ExternalDecoder_CleanStateCallback clean_state,
1469 ExternalDecoder_HasDelayedFrameCallback has_delayed_frame,
1470 ExternalDecoder_DisposeCallback dispose,
1471 ExternalDecoder_DtorCallback dtor);
1473 virtual void Dispose ();
1475 public:
1476 // If MediaFrame->decoder_specific_data is non-NULL, this method is called in ~MediaFrame.
1477 virtual void Cleanup (MediaFrame *frame);
1478 virtual void CleanState ();
1479 virtual bool HasDelayedFrame ();
1481 virtual const char *GetName () { return name; }
1485 * ExternalDecoderInfo
1488 /* @CBindingRequisite */
1489 typedef bool (* ExternalDecoderInfo_SupportsCallback) (void *instance, const char *codec);
1490 /* @CBindingRequisite */
1491 typedef IMediaDecoder * (* ExternalDecoderInfo_Create) (void *instance, Media *media, IMediaStream *stream);
1492 /* @CBindingRequisite */
1493 typedef void (* ExternalDecoderInfo_dtor) (void *instance);
1495 class ExternalDecoderInfo : public DecoderInfo {
1496 private:
1497 void *instance;
1498 char *name;
1499 ExternalDecoderInfo_SupportsCallback supports;
1500 ExternalDecoderInfo_Create create;
1501 ExternalDecoderInfo_dtor dtor;
1503 public:
1504 /* @GenerateCBinding */
1505 ExternalDecoderInfo (void *instance, const char *name, ExternalDecoderInfo_SupportsCallback supports, ExternalDecoderInfo_Create create, ExternalDecoderInfo_dtor dtor);
1507 virtual bool Supports (const char *codec);
1508 virtual IMediaDecoder *Create (Media *media, IMediaStream *stream);
1510 virtual ~ExternalDecoderInfo ();
1512 virtual const char *GetName () { return name; }
1516 * ASX demuxer
1518 class ASXDemuxer : public IMediaDemuxer {
1519 private:
1520 Playlist *playlist;
1522 protected:
1523 virtual ~ASXDemuxer ();
1524 virtual MediaResult SeekInternal (guint64 pts) { return MEDIA_FAIL; }
1526 virtual void GetFrameAsyncInternal (IMediaStream *stream) { ReportErrorOccurred ("GetFrameAsync isn't supported for ASXDemuxer"); }
1527 virtual void OpenDemuxerAsyncInternal ();
1528 virtual void SeekAsyncInternal (guint64 seekToTime) {}
1529 virtual void SwitchMediaStreamAsyncInternal (IMediaStream *stream) {}
1531 public:
1532 ASXDemuxer (Media *media, IMediaSource *source);
1533 virtual void Dispose ();
1535 virtual bool IsPlaylist () { return true; }
1536 virtual Playlist *GetPlaylist () { return playlist; }
1537 virtual const char *GetName () { return "ASXDemuxer"; }
1540 class ASXDemuxerInfo : public DemuxerInfo {
1541 public:
1542 virtual MediaResult Supports (IMediaSource *source);
1543 virtual IMediaDemuxer *Create (Media *media, IMediaSource *source);
1544 virtual const char *GetName () { return "ASXDemuxer"; }
1547 class MarkerStream : public IMediaStream {
1548 private:
1549 MediaMarkerFoundClosure *closure;
1550 Mutex mutex;
1551 List list; // a list of markers found while there were no callback.
1553 protected:
1554 virtual ~MarkerStream () {}
1556 public:
1557 MarkerStream (Media *media);
1558 virtual void Dispose ();
1560 virtual MediaStreamType GetType () { return MediaTypeMarker; }
1562 void SetCallback (MediaMarkerFoundClosure *closure);
1564 // Since the markers are taking the wrong way through the pipeline
1565 // (it's the pipeline who is pushing the markers up to the consumer,
1566 // not the consumer reading new markers), this works in the following way:
1567 // The demuxer reaches a marker somehow, creates a MediaFrame with the marker data and calls MarkerFound on the MarkerStream.
1568 // The MarkerStream calls the decoder to decode the frame.
1569 // The decoder must create an instance of MediaMarker and store it in the frame's buffer.
1570 // The MarkerStream then calls the closure with the MediaMarker.
1571 // Cleanup:
1572 // - The stream (in MarkerFound) frees the MediaMarker.
1573 // - The demuxer frees the MediaFrame, and the original frame buffer (before decoding).
1574 void MarkerFound (MediaFrame *frame);
1576 virtual void FrameEnqueued ();
1577 MediaMarker *Pop ();
1580 class PassThroughDecoder : public IMediaDecoder {
1581 protected:
1582 virtual ~PassThroughDecoder () {}
1583 virtual void DecodeFrameAsyncInternal (MediaFrame *frame);
1584 virtual void OpenDecoderAsyncInternal ();
1586 public:
1587 PassThroughDecoder (Media *media, IMediaStream *stream);
1588 virtual void Dispose ();
1590 virtual const char *GetName () { return "PassThroughDecoder"; }
1593 class PassThroughDecoderInfo : public DecoderInfo {
1594 public:
1595 virtual bool Supports (const char *codec);
1596 virtual IMediaDecoder *Create (Media *media, IMediaStream *stream)
1598 return new PassThroughDecoder (media, stream);
1600 virtual const char *GetName () { return "PassThroughDecoder"; }
1603 class NullDecoder : public IMediaDecoder {
1604 private:
1605 // Video data
1606 guint8 *logo;
1607 guint32 logo_size;
1609 // Audio datarf
1610 guint64 prev_pts;
1612 MediaResult DecodeVideoFrame (MediaFrame *frame);
1613 MediaResult DecodeAudioFrame (MediaFrame *frame);
1614 MediaResult OpenAudio ();
1615 MediaResult OpenVideo ();
1617 protected:
1618 virtual ~NullDecoder () {}
1619 virtual void DecodeFrameAsyncInternal (MediaFrame *frame);
1620 virtual void OpenDecoderAsyncInternal ();
1622 public:
1623 NullDecoder (Media *media, IMediaStream *stream);
1624 virtual void Dispose ();
1626 virtual const char *GetName () { return "NullDecoder"; }
1629 class NullDecoderInfo : public DecoderInfo {
1630 public:
1631 virtual bool Supports (const char *codec);
1633 virtual IMediaDecoder *Create (Media *media, IMediaStream *stream)
1635 return new NullDecoder (media, stream);
1637 virtual const char *GetName () { return "NullDecoder"; }
1640 #endif