1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * pipeline.h: Pipeline for the media
6 * Moonlight List (moonlight-list@lists.ximian.com)
8 * Copyright 2007 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
14 #ifndef __MOON_PIPELINE_H_
15 #define __MOON_PIPELINE_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
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)
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
62 * set state to playing
63 * set flag that we need more frames
64 * enqueue a few frame requests
67 * clear the queue of requested frames (no need to wait until frames being decoded are finished)
69 * set state to stopped
72 * if not playing, return
73 * if no decoded frames, return
75 * pop a decoded video+audio frame
77 * draw/play a decoded video/audio frame(s)
78 * enqueue more frame requests (one for each drawn/played)
81 * seek to the desired position
82 * enqueue a few frame requests
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
93 * add the decoded frame to the queue of decoded frames
113 class IImageConverter
;
115 class ProgressiveSource
;
116 class MediaMarkerFoundClosure
;
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
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
);
157 #include "dependencyobject.h"
161 #include "application.h"
166 class MediaClosure
: public EventObject
{
168 MediaCallback
*callback
;
172 EventObject
*context
; // The property of whoever creates the closure.
173 const char *description
;
174 void Init (Media
*media
, MediaCallback
*callback
, EventObject
*context
);
177 virtual ~MediaClosure () {}
178 MediaClosure (Type::Kind object_type
, Media
*media
, MediaCallback
*callback
, EventObject
*context
);
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
{
199 MediaDisposeObjectClosure (Media
*media
, MediaCallback
*callback
, EventObject
*context
);
200 virtual void Dispose ();
204 * MediaReportSeekCompletedClosure
206 class MediaReportSeekCompletedClosure
: public MediaClosure
{
211 virtual ~MediaReportSeekCompletedClosure ();
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
{
226 IMediaStream
*stream
;
229 virtual ~MediaGetFrameClosure ();
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 * MediaMarkerFoundClosure
242 class MediaMarkerFoundClosure
: public MediaClosure
{
247 virtual ~MediaMarkerFoundClosure () {}
250 MediaMarkerFoundClosure (Media
*media
, MediaCallback
*callback
, MediaElement
*context
);
251 virtual void Dispose ();
253 MediaMarker
*GetMarker () { return marker
; }
254 void SetMarker (MediaMarker
*marker
);
260 class MediaSeekClosure
: public MediaClosure
{
265 virtual ~MediaSeekClosure () {}
268 MediaSeekClosure (Media
*media
, MediaCallback
*callback
, IMediaDemuxer
*context
, guint64 pts
);
270 IMediaDemuxer
*GetDemuxer () { return (IMediaDemuxer
*) GetContext (); }
271 guint64
GetPts () { return pts
; }
275 * *Info classes used to register codecs, demuxers and converters.
280 MediaInfo
*next
; // Used internally by Media.
281 MediaInfo () : next (NULL
) {}
282 virtual ~MediaInfo () {}
283 virtual const char *GetName () { return "Unknown"; }
286 class DecoderInfo
: public MediaInfo
{
288 virtual bool Supports (const char *codec
) = 0;
289 virtual IMediaDecoder
*Create (Media
*media
, IMediaStream
*stream
) = 0;
291 virtual ~DecoderInfo () {}
294 class DemuxerInfo
: public MediaInfo
{
296 // <buffer> points to the first <length> bytes of a file.
297 // <length> is guaranteed to be at least 16 bytes.
298 // Possible return values:
299 // - MEDIA_SUCCESS: the demuxer supports this source
300 // - MEDIA_FAIL: the demuxer does not support this source
301 // - 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.
302 virtual MediaResult
Supports (IMediaSource
*source
) = 0;
303 virtual IMediaDemuxer
*Create (Media
*media
, IMediaSource
*source
) = 0;
306 class ConverterInfo
: public MediaInfo
{
308 virtual bool Supports (MoonPixelFormat input
, MoonPixelFormat output
) = 0;
309 virtual IImageConverter
*Create (Media
*media
, VideoStream
*stream
) = 0;
315 /* @Namespace=None */
316 class ProgressEventArgs
: public EventArgs
{
320 ProgressEventArgs (double progress
)
322 this->progress
= progress
;
330 class MediaWork
: public List::Node
{
332 MediaClosure
*closure
;
333 MediaWork (MediaClosure
*closure
);
334 virtual ~MediaWork ();
340 class IMediaObject
: public EventObject
{
344 // Media event handling
345 // media needs to support event handling on all threads, and EventObject isn't thread-safe
346 class EventData
: public List::Node
{
349 EventHandler handler
;
350 EventObject
*context
;
351 bool invoke_on_main_thread
;
352 EventData (int event_id
, EventHandler handler
, EventObject
*context
, bool invoke_on_main_thread
);
353 virtual ~EventData ();
355 class EmitData
: public List::Node
{
358 EventHandler handler
;
359 EventObject
*context
;
361 EmitData (int event_id
, EventHandler handler
, EventObject
*context
, EventArgs
*args
);
362 virtual ~EmitData ();
364 List
*events
; // list of event handlers
365 List
*emit_on_main_thread
; // list of emit calls to emit on main thread
368 void EmitList (List
*list
);
369 void EmitListMain ();
370 static void EmitListCallback (EventObject
*obj
);
373 virtual ~IMediaObject () {}
376 IMediaObject (Type::Kind kind
, Media
*media
);
377 virtual void Dispose ();
379 /* @GenerateCBinding,GeneratePInvoke */
380 Media
*GetMediaReffed ();
381 void SetMedia (Media
*value
);
383 void ReportErrorOccurred (ErrorEventArgs
*args
);
384 /* @GenerateCBinding */
385 void ReportErrorOccurred (const char *message
);
386 void ReportErrorOccurred (MediaResult result
);
388 // All the event methods are thread-safe
389 void AddSafeHandler (int event_id
, EventHandler handler
, EventObject
*context
, bool invoke_on_main_thread
= true);
390 void RemoveSafeHandlers (EventObject
*context
);
391 void EmitSafe (int event_id
, EventArgs
*args
= NULL
);
394 class IMediaStream
: public IMediaObject
{
399 bool input_ended
; // end of stream reached in demuxer
400 bool output_ended
; // end of stream reached in decoder
401 guint64 first_pts
; // The first pts in the stream, initialized to G_MAXUINT64
402 guint64 last_popped_pts
; // The pts of the last frame returned, initialized to G_MAXUINT64
403 guint64 last_enqueued_pts
; // The pts of the last frae enqueued, initialized to G_MAXUINT64
404 guint64 last_available_pts
; // The last pts available, initialized to 0. Note that this field won't be correct for streams which CanSeekToPts.
405 Queue queue
; // Our queue of demuxed frames
406 IMediaDecoder
*decoder
;
409 virtual ~IMediaStream () {}
410 virtual void FrameEnqueued () {}
412 static char *CreateCodec (int codec_id
); // converts fourcc int value into a string
414 class StreamNode
: public List::Node
{
418 StreamNode (MediaFrame
*frame
);
419 virtual ~StreamNode ();
420 MediaFrame
*GetFrame () { return frame
; }
423 IMediaStream (Type::Kind kind
, Media
*media
);
424 virtual void Dispose ();
426 // Video, Audio, Markers, etc.
427 virtual MediaStreamType
GetType () = 0; // TODO: This should be removed, it clashes with GetType in EventObject.
428 /* @GenerateCBinding */
429 virtual MediaStreamType
GetStreamType () { return GetType (); }
430 const char *GetStreamTypeName ();
432 IMediaDecoder
*GetDecoder ();
433 void SetDecoder (IMediaDecoder
*value
);
435 // If this stream is enabled (producing output).
436 // A file might have several audio streams,
437 // and live streams might have several video streams with different bitrates.
438 bool IsEnabled () { return enabled
; }
439 /* @GenerateCBinding */
440 const char *GetCodec () { return codec
; }
442 // User defined context value.
443 void *GetContext () { return context
; }
444 void SetContext (void *context
) { this->context
= context
; }
446 bool GetSelected () { return selected
; }
447 void SetSelected (bool value
);
449 guint32
GetBitrate ();
454 guint64 duration
; // 100-nanosecond units (pts)
455 char *codec
; // freed upon destruction
456 // The minimum amount of padding any other part of the pipeline needs for frames from this stream.
457 // Used by the demuxer when reading frames, ensures that there are at least min_padding extra bytes
458 // at the end of the frame data (all initialized to 0).
460 // 0-based index of the stream in the media
461 // set by the demuxer, until then its value must be -1
464 void EnqueueFrame (MediaFrame
*frame
);
465 MediaFrame
*PopFrame ();
466 bool IsQueueEmpty ();
467 bool IsInQueue (MediaFrame
*frame
);
469 guint64
GetFirstPts () { return first_pts
; }
470 guint64
GetLastPoppedPts () { return last_popped_pts
; }
471 guint64
GetLastEnqueuedPts () { return last_enqueued_pts
; }
472 void SetLastAvailablePts (guint64 value
) { last_available_pts
= MAX (value
, last_available_pts
); }
473 guint64
GetLastAvailablePts () { return last_available_pts
; }
474 guint64
GetBufferedSize (); // Returns the time between the last frame returned and the last frame available (buffer time)
476 /* @GenerateCBinding */
477 int GetExtraDataSize () { return extra_data_size
; }
478 /* @GenerateCBinding */
479 void SetExtraDataSize (int value
) { extra_data_size
= value
; }
480 /* @GenerateCBinding */
481 void *GetExtraData () { return extra_data
; }
482 /* @GenerateCBinding */
483 void SetExtraData (void *value
) { extra_data
= value
; }
484 /* @GenerateCBinding */
485 int GetCodecId () { return codec_id
; }
486 /* @GenerateCBinding */
487 void SetCodecId (int value
) { codec_id
= value
; }
488 /* @GenerateCBinding */
489 guint64
GetDuration () { return duration
; }
490 /* @GenerateCBinding */
491 void SetDuration (guint64 value
) { duration
= value
; }
493 bool GetInputEnded ();
494 void SetInputEnded (bool value
);
495 bool GetOutputEnded ();
496 void SetOutputEnded (bool value
);
498 IMediaDemuxer
*GetDemuxer ();
500 void ReportSeekCompleted ();
502 void PrintBufferInformation ();
504 const static int FirstFrameEnqueuedEvent
;
510 class Media
: public IMediaObject
{
512 static ConverterInfo
*registered_converters
;
513 static DemuxerInfo
*registered_demuxers
;
514 static DecoderInfo
*registered_decoders
;
515 static bool registering_ms_codecs
;
516 static bool registered_ms_codecs
;
520 guint64 buffering_time
; // Access must be protected with mutex.
521 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.
524 IMediaSource
*source
;
525 IMediaDemuxer
*demuxer
;
531 bool error_reported
; // If an error has been reported.
532 bool buffering_enabled
;
533 bool in_open_internal
; // detect recursive calls to OpenInternal
535 double download_progress
;
536 double buffering_progress
;
538 PlaylistRoot
*playlist
;
540 // Determines the container type and selects a demuxer. We have support for mp3 and asf demuxers.
541 // Also opens the demuxer.
542 // This method is supposed to be called multiple times, until either 'error_reported' is true or this method
543 // returns true. It will pick up wherever it left working last time.
544 bool SelectDemuxerAsync ();
546 // Selects decoders according to stream info.
547 // - Default is to use any MS decoder if available (and applicable), otherwise ffmpeg.
548 // Overridable by MOONLIGHT_OVERRIDES, set ms-codecs=no to disable ms codecs, and ffmpeg-codecs=no to disable ffempg codecs
549 // This method is supposed to be called multiple times, until either 'error_reported' is true or this method
550 // returns true. It will pick up wherever it left working last time.
551 bool SelectDecodersAsync ();
553 // This method is supposed to be called multiple times, until the media has been successfully opened or an error occurred.
554 void OpenInternal ();
555 static MediaResult
OpenInternal (MediaClosure
*closure
);
556 static MediaResult
DisposeObjectInternal (MediaClosure
*closure
);
558 static MediaResult
StopCallback (MediaClosure
*closure
);
559 static MediaResult
PauseCallback (MediaClosure
*closure
);
560 static MediaResult
PlayCallback (MediaClosure
*closure
);
569 Media (PlaylistRoot
*root
);
571 virtual void Dispose ();
573 static bool InMediaThread ();
574 bool EnqueueWork (MediaClosure
*closure
, bool wakeup
= true);
576 // Calls obj->Dispose on the media thread.
577 void DisposeObject (EventObject
*obj
);
579 // Initialize the Media.
580 // These methods may raise MediaError events.
581 void Initialize (Downloader
*downloader
, const char *PartName
); // MediaElement.SetSource (dl, 'PartName');
582 void Initialize (const char *uri
); // MediaElement.Source = 'uri';
583 void Initialize (IMediaDemuxer
*demuxer
); // MediaElement.SetSource (demuxer);
584 void Initialize (IMediaSource
*source
);
586 // Start opening the media.
587 // When done, OpenCompleted event is raised.
588 // In case of failure, MediaError event is raised
591 void ReportOpenDemuxerCompleted (); // This method is called by the demuxer when it has opened.
592 void ReportOpenDecoderCompleted (IMediaDecoder
*decoder
); // This method is called by any of the decoders when it has opened.
593 void ReportOpenCompleted (); // Raise the OpenCompleted event.
595 void ReportDownloadProgress (double progress
);
596 void ReportBufferingProgress (double progress
);
599 void PlayAsync (); // Raises CurrentStateChanged
600 void PauseAsync (); // Raises CurrentStateChanged
601 void StopAsync (); // Raises CurrentStateChanged
602 // Seek to the specified pts
603 // When done, SeekCompleted is raised
604 // In case of failure, MediaError is raised.
605 void SeekAsync (guint64 pts
);
606 void ReportSeekCompleted (guint64 pts
); // This method is called by IMediaDemuxer when the seek is completed. Raises the SeekCompleted event.
608 void ClearQueue (); // Clears the queue and make sure the thread has finished processing what it's doing
611 void SetBufferingTime (guint64 buffering_time
);
612 guint64
GetBufferingTime ();
614 void SetBufferingEnabled (bool value
);
616 IMediaSource
*GetSource () { return source
; }
617 IMediaDemuxer
*GetDemuxer () { return demuxer
; }
618 const char *GetFile () { return file
; }
619 const char *GetUri () { return uri
; }
620 void SetFileOrUrl (const char *value
);
622 static void Warning (MediaResult result
, const char *format
, ...);
623 // A list of MediaMarker::Node.
624 // This is the list of markers found in the metadata/headers (not as a separate stream).
625 // Will never return NULL.
627 double GetDownloadProgress () { return download_progress
; }
628 double GetBufferingProgress () { return buffering_progress
; }
630 PlaylistRoot
*GetPlaylistRoot ();
632 bool IsOpened () { return opened
; }
633 bool IsOpening () { return opening
; }
634 bool IsStopped () { return stopped
; }
636 void RetryHttp (ErrorEventArgs
*args
);
638 void ReportErrorOccurred (ErrorEventArgs
*args
);
639 void ReportErrorOccurred (const char *message
);
640 void ReportErrorOccurred (MediaResult result
);
642 bool HasReportedError () { return error_reported
; }
644 const static int OpeningEvent
;
645 const static int OpenCompletedEvent
;
646 const static int SeekingEvent
;
647 const static int SeekCompletedEvent
;
648 const static int CurrentStateChangedEvent
;
649 const static int MediaErrorEvent
;
650 const static int DownloadProgressChangedEvent
;
651 const static int BufferingProgressChangedEvent
;
653 // Registration functions
654 // This class takes ownership of the infos and will delete them (not free) when the Media is shutdown.
655 static void RegisterDemuxer (DemuxerInfo
*info
);
656 /* @GenerateCBinding */
657 static void RegisterDecoder (DecoderInfo
*info
);
658 static void RegisterConverter (ConverterInfo
*info
);
660 static void RegisterMSCodecs ();
661 static bool IsMSCodecsInstalled ();
663 static void Initialize ();
664 static void Shutdown ();
670 * The most important requirement for the thread pool is that it never executes several work items for a single Media instance simultaneously.
671 * 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
672 * a Media instance which is not in the list.
674 class MediaThreadPool
{
676 static pthread_mutex_t mutex
;
677 static pthread_cond_t condition
; /* signalled when work has been added */
678 static pthread_cond_t completed_condition
; /* signalled when work has completed executing */
679 static const int max_threads
= 4; /* max 4 threads for now */
680 static int count
; // the number of created threads
681 static pthread_t threads
[max_threads
]; // array of threads
682 static bool valid
[max_threads
]; // specifies which thread indices are valid.
683 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.
684 static Deployment
*deployments
[max_threads
]; // array of deployments currently being worked on.
685 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).
688 static void *WorkerLoop (void *data
);
691 // Removes all enqueued work for the specified media.
692 static void RemoveWork (Media
*media
);
693 // Waits until all enqueued work for the specified deployment has finished
694 // executing and there is no more work for the specified deployment. Note that
695 // it does not touch the queue, it just waits for the threads to finish cleaning
697 static void WaitForCompletion (Deployment
*deployment
); /* Main thread only */
698 static void AddWork (MediaClosure
*closure
, bool wakeup
);
699 static void WakeUp ();
700 static void Initialize ();
701 static void Shutdown ();
703 // this method checks if the current thread is a thread-pool thread
704 static bool IsThreadPoolThread ();
707 class MediaFrame
: public EventObject
{
712 virtual ~MediaFrame ();
715 MediaFrame (IMediaStream
*stream
);
716 /* @GenerateCBinding,GeneratePInvoke */
717 MediaFrame (IMediaStream
*stream
, guint8
*buffer
, guint32 buflen
, guint64 pts
, bool keyframe
);
720 /* @GenerateCBinding */
721 void AddState (MediaFrameState state
) { this->state
|= (guint16
) state
; } // There's no way of "going back" to an earlier state
722 bool IsDecoded () { return (((MediaFrameState
) state
) & MediaFrameDecoded
) == MediaFrameDecoded
; }
723 bool IsDemuxed () { return (((MediaFrameState
) state
) & MediaFrameDemuxed
) == MediaFrameDemuxed
; }
724 bool IsConverted () { return (((MediaFrameState
) state
) & MediaFrameConverted
) == MediaFrameConverted
; }
725 bool IsPlanar () { return (((MediaFrameState
) state
) & MediaFramePlanar
) == MediaFramePlanar
; }
726 /* @GenerateCBinding */
727 bool IsKeyFrame () { return (((MediaFrameState
) state
) & MediaFrameKeyFrame
) == MediaFrameKeyFrame
; }
728 bool IsMarker () { return (((MediaFrameState
) state
) & MediaFrameMarker
) == MediaFrameMarker
; }
730 IMediaStream
*stream
;
732 void *decoder_specific_data
; // data specific to the decoder
733 guint64 pts
; // Set by the demuxer
734 guint64 duration
; // Set by the demuxer
736 guint16 state
; // Current state of the frame
737 guint16 event
; // special frame event if non-0
739 // The demuxer sets these to the encoded data which the
740 // decoder then uses and replaces with the decoded data.
745 guint8
*data_stride
[4]; // Set by the decoder
746 int srcSlideY
; // Set by the decoder
747 int srcSlideH
; // Set by the decoder
748 int srcStride
[4]; // Set by the decoder
750 // The decoded size of the frame (might be bigger or smaller than the size of the stream).
751 // 0 = the size specified in the stream
755 /* @GenerateCBinding */
756 guint32
GetBufLen () { return buflen
; }
757 /* @GenerateCBinding */
758 void SetBufLen (guint32 value
) { buflen
= value
; }
759 /* @GenerateCBinding */
760 guint8
* GetBuffer () { return buffer
; }
761 /* @GenerateCBinding */
762 void SetBuffer (guint8
*value
) { buffer
= value
; }
763 /* @GenerateCBinding */
764 guint64
GetPts () { return pts
; }
765 /* @GenerateCBinding */
766 void SetPts (guint64 value
) { pts
= value
; }
768 /* @GenerateCBinding */
769 gint32
GetWidth () { return width
; }
770 /* @GenerateCBinding */
771 void SetWidth (gint32 value
) { width
= value
; }
772 /* @GenerateCBinding */
773 gint32
GetHeight () { return height
; }
774 /* @GenerateCBinding */
775 void SetHeight (gint32 value
) { height
= value
; }
776 /* @GenerateCBinding */
777 void SetDataStride (guint8
*a
, guint8
*b
, guint8
*c
, guint8
*d
);
778 /* @GenerateCBinding */
779 void SetSrcStride (int a
, int b
, int c
, int d
);
780 /* @GenerateCBinding */
781 void SetSrcSlideY (int value
);
782 /* @GenerateCBinding */
783 void SetSrcSlideH (int value
);
784 /* @GenerateCBinding */
785 void SetDecoderSpecificData (void *value
) { decoder_specific_data
= value
; }
790 class MediaMarker
: public EventObject
{
791 guint64 pts
; // 100-nanosecond units (pts)
796 virtual ~MediaMarker ();
799 class Node
: public List::Node
{
801 Node (MediaMarker
*m
)
815 MediaMarker (const char *type
, const char *text
, guint64 pts
);
817 const char *Type () { return type
; }
818 const char *Text () { return text
; }
819 guint64
Pts () { return pts
; }
824 class IMediaDemuxer
: public IMediaObject
{
826 IMediaStream
**streams
;
830 IMediaStream
*pending_stream
; // the stream we're waiting for a frame for.
831 bool pending_fill_buffers
;
834 static MediaResult
ReportSeekCompletedCallback (MediaClosure
*closure
);
835 static MediaResult
GetFrameCallback (MediaClosure
*closure
);
836 static MediaResult
FillBuffersCallback (MediaClosure
*closure
);
837 static MediaResult
OpenCallback (MediaClosure
*closure
);
838 static MediaResult
SeekCallback (MediaClosure
*closure
);
840 void FillBuffersInternal ();
843 IMediaSource
*source
;
845 IMediaDemuxer (Type::Kind kind
, Media
*media
, IMediaSource
*source
);
846 IMediaDemuxer (Type::Kind kind
, Media
*media
);
848 virtual ~IMediaDemuxer () {}
850 void SetStreams (IMediaStream
**streams
, int count
);
851 gint32
AddStream (IMediaStream
*stream
);
853 virtual void CloseDemuxerInternal () {};
854 virtual void GetDiagnosticAsyncInternal (MediaStreamSourceDiagnosticKind diagnosticKind
) {}
855 virtual void GetFrameAsyncInternal (IMediaStream
*stream
) = 0;
856 virtual void OpenDemuxerAsyncInternal () = 0;
857 virtual void SeekAsyncInternal (guint64 pts
) = 0;
858 virtual void SwitchMediaStreamAsyncInternal (IMediaStream
*stream
) = 0;
861 void EnqueueReportSeekCompleted (guint64 pts
);
862 void EnqueueGetFrame (IMediaStream
*stream
);
863 void EnqueueSeek (guint64 pts
);
866 virtual void Dispose ();
868 void CloseDemuxer () {};
869 void GetDiagnosticAsync (MediaStreamSourceDiagnosticKind diagnosticKind
) {}
870 void GetFrameAsync (IMediaStream
*stream
);
871 void OpenDemuxerAsync ();
872 void SeekAsync (guint64 pts
);
873 void SwitchMediaStreamAsync (IMediaStream
*stream
);
875 /* @GenerateCBinding,GeneratePInvoke */
876 void ReportOpenDemuxerCompleted ();
877 /* @GenerateCBinding,GeneratePInvoke */
878 void ReportGetFrameCompleted (MediaFrame
*frame
);
879 /* @GenerateCBinding,GeneratePInvoke */
880 void ReportGetFrameProgress (double bufferingProgress
);
881 /* @GenerateCBinding,GeneratePInvoke */
882 void ReportSeekCompleted (guint64 pts
);
883 /* @GenerateCBinding,GeneratePInvoke */
884 void ReportSwitchMediaStreamCompleted (IMediaStream
*stream
);
885 /* @GenerateCBinding,GeneratePInvoke */
886 void ReportGetDiagnosticCompleted (MediaStreamSourceDiagnosticKind diagnosticKind
, gint64 diagnosticValue
);
888 guint64
GetBufferedSize ();
890 void ClearBuffers ();
892 void PrintBufferInformation ();
894 int GetStreamCount () { return stream_count
; }
895 IMediaStream
*GetStream (int index
);
896 // Gets the longest duration from all the streams
897 virtual guint64
GetDuration (); // 100-nanosecond units (pts)
898 virtual const char *GetName () = 0;
899 virtual void UpdateSelected (IMediaStream
*stream
) {};
901 guint64
GetLastAvailablePts ();
902 IMediaSource
*GetSource () { return source
; }
903 bool IsOpened () { return opened
; }
904 bool IsOpening () { return opening
; }
906 virtual bool IsPlaylist () { return false; }
907 virtual Playlist
*GetPlaylist () { return NULL
; }
910 class IMediaDecoder
: public IMediaObject
{
915 MoonPixelFormat pixel_format
; // The pixel format this codec outputs. Open () should fill this in.
916 IMediaStream
*stream
;
917 Queue queue
; // the list of frames to decode.
919 static MediaResult
DecodeFrameCallback (MediaClosure
*closure
);
921 class FrameNode
: public List::Node
{
925 FrameNode (MediaFrame
*f
) : frame (f
)
930 virtual ~FrameNode ()
937 virtual ~IMediaDecoder () {}
939 virtual void DecodeFrameAsyncInternal (MediaFrame
*frame
) = 0;
940 virtual void OpenDecoderAsyncInternal () = 0;
942 // InputEnded is called when there is no more input. If the codec has delayed frames,
943 // it must call ReportDecodeFrameCompleted with those frames (all of them).
944 virtual void InputEnded () { };
947 IMediaDecoder (Type::Kind kind
, Media
*media
, IMediaStream
*stream
);
948 virtual void Dispose ();
950 // If MediaFrame->decoder_specific_data is non-NULL, this method is called in ~MediaFrame.
951 virtual void Cleanup (MediaFrame
*frame
) {}
952 virtual void CleanState () {}
953 virtual bool HasDelayedFrame () { return false; }
955 virtual const char *GetName () { return GetTypeName (); }
957 // This method is called when the demuxer has finished seeking.
958 void ReportSeekCompleted ();
959 // This method is called when the demuxer is out of data.
960 void ReportInputEnded ();
961 /* @GenerateCBinding */
962 void ReportDecodeFrameCompleted (MediaFrame
*frame
);
963 /* @GenerateCBinding */
964 void ReportOpenDecoderCompleted ();
965 /* @GenerateCBinding */
966 void SetPixelFormat (MoonPixelFormat value
) { pixel_format
= value
; }
968 void DecodeFrameAsync (MediaFrame
*frame
, bool enqueue_always
);
969 void OpenDecoderAsync ();
971 bool IsOpening () { return opening
; }
972 bool IsOpened () { return opened
; }
973 MoonPixelFormat
GetPixelFormat () { return pixel_format
; }
974 IMediaStream
*GetStream () { return stream
; }
976 bool IsDecoderQueueEmpty () { return queue
.IsEmpty (); }
981 * Inherit from this class to provide image converters (yuv->rgb for instance)
983 class IImageConverter
: public IMediaObject
{
985 virtual ~IImageConverter () {}
988 MoonPixelFormat output_format
;
989 MoonPixelFormat input_format
;
992 IImageConverter (Type::Kind kind
, Media
*media
, VideoStream
*stream
);
994 virtual MediaResult
Open () = 0;
995 virtual MediaResult
Convert (guint8
*src
[], int srcStride
[], int srcSlideY
, int srcSlideH
, guint8
*dest
[], int dstStride
[]) = 0;
1001 class IMediaSource
: public IMediaObject
{
1003 // General locking behaviour:
1004 // All protected virtual methods must be called with the mutex
1005 // locked. If a derived virtual method needs to lock, it needs
1006 // to be implemented as a protected virtual method xxxInternal
1007 // which requires the mutex to be locked, and then a public
1008 // method in IMediaSource which does the locking. No public method
1009 // in IMediaSource may be called from the xxxInternal methods.
1010 pthread_mutex_t mutex
;
1011 pthread_cond_t condition
;
1014 virtual ~IMediaSource ();
1019 // All these methods must/will be called with the lock locked.
1020 virtual gint32
ReadInternal (void *buf
, guint32 n
);
1021 virtual gint32
PeekInternal (void *buf
, guint32 n
);
1022 virtual bool SeekInternal (gint64 offset
, int mode
);
1023 virtual gint64
GetLastAvailablePositionInternal () { return -1; }
1024 virtual gint64
GetPositionInternal ();
1025 virtual gint64
GetSizeInternal ();
1028 IMediaSource (Type::Kind kind
, Media
*media
);
1029 virtual void Dispose ();
1031 // Initializes this stream (and if it succeeds, it can be read from later on).
1032 // streams based on remote content (live/progress) should contact the server
1033 // and try to start downloading content
1034 // file streams should try to open the file
1035 virtual MediaResult
Initialize () = 0;
1036 virtual MediaSourceType
GetType () = 0;
1038 // Reads 'n' bytes into 'buf'. If data isn't available it will
1039 // read the amount of data available. Returns the number of bytes read.
1040 // This method will lock the mutex.
1041 gint32
ReadSome (void *buf
, guint32 n
);
1043 // Reads 'n' bytes into 'buf'.
1044 // Returns false if 'n' bytes couldn't be read.
1045 // This method will lock the mutex.
1046 bool ReadAll (void *buf
, guint32 n
);
1048 // Reads 'n' bytes into 'buf', starting at position 'start'. If 'start' is -1,
1049 // then start at the current position. If data isn't available it will
1050 // read the amount of data available. Returns false if 'n' bytes couldn't be
1052 // This method will lock the mutex.
1053 bool Peek (void *buf
, guint32 n
);
1055 virtual bool CanSeek () { return true; }
1057 // Seeks to the specified 'offset', using the specified 'mode'.
1058 // This method will lock the mutex.
1059 bool Seek (gint64 offset
, int mode
= SEEK_CUR
);
1061 // Seeks to the specified 'pts'.
1062 virtual bool CanSeekToPts () { return false; }
1063 virtual MediaResult
SeekToPts (guint64 pts
) { return MEDIA_FAIL
; }
1065 // Returns the current reading position
1066 // This method will lock the mutex.
1067 gint64
GetPosition ();
1069 // Returns the size of the source. This method may return -1 if the
1070 // size isn't known.
1071 // This method will lock the mutex.
1074 virtual bool Eof () = 0;
1076 // Returns the last available position
1077 // If the returned value is -1, then everything is available.
1078 // This method will lock the mutex.
1079 gint64
GetLastAvailablePosition ();
1081 // Checks if the specified position can be read
1082 // upon return, and if the position is not availble eof determines whether the position is not available because
1083 // the file isn't that big (eof = true), or the position hasn't been read yet (eof = false).
1084 // if the position is available, eof = false
1085 bool IsPositionAvailable (gint64 position
, bool *eof
);
1087 // If the derived class knows which demuxer it needs,
1088 // it should override this method and return a new demuxer.
1089 virtual IMediaDemuxer
*CreateDemuxer (Media
*media
) { return NULL
; }
1091 virtual const char *ToString () { return "IMediaSource"; }
1094 class ManagedStreamSource
: public IMediaSource
{
1096 ManagedStreamCallbacks stream
;
1099 virtual ~ManagedStreamSource ();
1101 virtual gint32
ReadInternal (void *buf
, guint32 n
);
1102 virtual gint32
PeekInternal (void *buf
, guint32 n
);
1103 virtual bool SeekInternal (gint64 offset
, int mode
);
1104 virtual gint64
GetPositionInternal ();
1105 virtual gint64
GetSizeInternal ();
1108 ManagedStreamSource (Media
*media
, ManagedStreamCallbacks
*stream
);
1110 virtual MediaResult
Initialize () { return MEDIA_SUCCESS
; }
1111 virtual MediaSourceType
GetType () { return MediaSourceTypeManagedStream
; }
1113 virtual bool Eof () { return GetPositionInternal () == GetSizeInternal (); }
1115 virtual const char *ToString () { return GetTypeName (); }
1118 class FileSource
: public IMediaSource
{
1129 virtual ~FileSource ();
1130 FileSource (Media
*media
, bool temp_file
);
1132 MediaResult
Open (const char *filename
);
1134 virtual gint32
ReadInternal (void *buf
, guint32 n
);
1135 virtual gint32
PeekInternal (void *buf
, guint32 n
);
1136 virtual bool SeekInternal (gint64 offset
, int mode
);
1137 virtual gint64
GetPositionInternal ();
1138 virtual gint64
GetSizeInternal ();
1141 FileSource (Media
*media
, const char *filename
);
1142 virtual void Dispose ();
1144 virtual MediaResult
Initialize ();
1145 virtual MediaSourceType
GetType () { return MediaSourceTypeFile
; }
1147 virtual bool Eof ();
1149 virtual const char *ToString () { return filename
; }
1151 const char *GetFileName () { return filename
; }
1154 class ProgressiveSource
: public FileSource
{
1158 // To avoid locking while reading and writing (since reading is done on
1159 // the media thread and writing on the main thread), we open two file
1160 // handlers, one for reading (in FileSource) and the other one here
1164 Cancellable
*cancellable
;
1166 virtual gint64
GetLastAvailablePositionInternal () { return size
== write_pos
? write_pos
: write_pos
& ~(1024*4-1); }
1167 virtual gint64
GetSizeInternal () { return size
; }
1169 static void data_write (void *data
, gint32 offset
, gint32 n
, void *closure
);
1170 static void notify_func (NotifyType type
, gint64 args
, void *closure
);
1171 static void delete_cancellable (EventObject
*data
);
1173 void Notify (NotifyType
, gint64 args
);
1175 void DownloadComplete ();
1176 void DownloadFailed ();
1177 void DataWrite (void *data
, gint32 offset
, gint32 n
);
1178 void NotifySize (gint64 size
);
1179 void SetTotalSize (gint64 size
);
1181 void CloseWriteFile ();
1184 virtual ~ProgressiveSource () {}
1187 ProgressiveSource (Media
*media
, const char *uri
);
1188 virtual void Dispose ();
1190 virtual MediaResult
Initialize ();
1191 virtual MediaSourceType
GetType () { return MediaSourceTypeProgressive
; }
1197 class MemorySource
: public IMediaSource
{
1206 virtual ~MemorySource ();
1208 virtual gint32
ReadInternal (void *buf
, guint32 n
);
1209 virtual gint32
PeekInternal (void *buf
, guint32 n
);
1210 virtual bool SeekInternal (gint64 offset
, int mode
);
1211 virtual gint64
GetSizeInternal () { return size
; }
1212 virtual gint64
GetPositionInternal () { return pos
+ start
; }
1213 virtual gint64
GetLastAvailablePositionInternal () { return start
+ size
; }
1216 MemorySource (Media
*media
, void *memory
, gint32 size
, gint64 start
= 0, bool owner
= true);
1218 void *GetMemory () { return memory
; }
1219 void Release (void) { delete this; }
1221 void SetOwner (bool value
) { owner
= value
; }
1222 gint64
GetStart () { return start
; }
1224 virtual MediaResult
Initialize () { return MEDIA_SUCCESS
; }
1225 virtual MediaSourceType
GetType () { return MediaSourceTypeMemory
; }
1227 virtual bool CanSeek () { return true; }
1228 virtual bool Eof () { return pos
>= size
; }
1230 virtual const char *ToString () { return "MemorySource"; }
1233 class VideoStream
: public IMediaStream
{
1235 virtual ~VideoStream ();
1240 IImageConverter
*converter
; // This stream has the ownership of the converter, it will be deleted upon destruction.
1241 guint32 bits_per_sample
;
1242 guint64 pts_per_frame
; // Duration (in pts) of each frame. Set to 0 if unknown.
1243 guint64 initial_pts
;
1248 VideoStream (Media
*media
);
1250 /* @GenerateCBinding,GeneratePInvoke */
1251 VideoStream (Media
*media
, int codec_id
, guint32 width
, guint32 height
, guint64 duration
, gpointer extra_data
, guint32 extra_data_size
);
1253 virtual MediaStreamType
GetType () { return MediaTypeVideo
; }
1255 guint32
GetBitsPerSample () { return bits_per_sample
; }
1256 guint32
GetPtsPerFrame () { return pts_per_frame
; }
1257 guint32
GetInitialPts () { return initial_pts
; }
1258 /* @GenerateCBinding */
1259 guint32
GetWidth () { return width
; }
1260 /* @GenerateCBinding */
1261 guint32
GetHeight () { return height
; }
1262 guint32
GetBitRate () { return bit_rate
; }
1265 class AudioStream
: public IMediaStream
{
1268 int input_bits_per_sample
;
1269 int input_block_align
;
1270 int input_sample_rate
;
1275 int output_bits_per_sample
;
1276 int output_block_align
;
1277 int output_sample_rate
;
1278 int output_channels
;
1279 int output_bit_rate
;
1281 virtual ~AudioStream () {}
1285 AudioStream (Media
*media
);
1287 /* @GenerateCBinding,GeneratePInvoke */
1288 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
);
1290 virtual MediaStreamType
GetType () { return MediaTypeAudio
; }
1292 // TODO: remove the non Input/Output accessors
1293 // wait until later since it is a two-way codec abi breakage.
1295 /* @GenerateCBinding */
1296 int GetBitsPerSample () { return input_bits_per_sample
; }
1297 /* @GenerateCBinding */
1298 void SetBitsPerSample (int value
) { output_bits_per_sample
= input_bits_per_sample
= value
; }
1299 /* @GenerateCBinding */
1300 int GetBlockAlign () { return input_block_align
; }
1301 /* @GenerateCBinding */
1302 void SetBlockAlign (int value
) { output_block_align
= input_block_align
= value
; }
1303 /* @GenerateCBinding */
1304 int GetSampleRate () { return input_sample_rate
; }
1305 /* @GenerateCBinding */
1306 void SetSampleRate (int value
) { output_sample_rate
= input_sample_rate
= value
; }
1307 /* @GenerateCBinding */
1308 int GetChannels () { return input_channels
; }
1309 /* @GenerateCBinding */
1310 void SetChannels (int value
) { output_channels
= input_channels
= value
; }
1311 /* @GenerateCBinding */
1312 int GetBitRate () { return input_bit_rate
; }
1313 /* @GenerateCBinding */
1314 void SetBitRate (int value
) { output_bit_rate
= input_bit_rate
= value
; }
1318 /* @GenerateCBinding */
1319 int GetInputBitsPerSample () { return input_bits_per_sample
; }
1320 /* @GenerateCBinding */
1321 void SetInputBitsPerSample (int value
) { input_bits_per_sample
= value
; }
1323 /* @GenerateCBinding */
1324 int GetInputBlockAlign () { return input_block_align
; }
1325 /* @GenerateCBinding */
1326 void SetInputBlockAlign (int value
) { input_block_align
= value
; }
1328 /* @GenerateCBinding */
1329 int GetInputSampleRate () { return input_sample_rate
; }
1330 /* @GenerateCBinding */
1331 void SetInputSampleRate (int value
) { input_sample_rate
= value
; }
1333 /* @GenerateCBinding */
1334 int GetInputChannels () { return input_channels
; }
1335 /* @GenerateCBinding */
1336 void SetInputChannels (int value
) { input_channels
= value
; }
1338 /* @GenerateCBinding */
1339 int GetInputBitRate () { return input_bit_rate
; }
1340 /* @GenerateCBinding */
1341 void SetInputBitRate (int value
) { input_bit_rate
= value
; }
1345 /* @GenerateCBinding */
1346 int GetOutputBitsPerSample () { return output_bits_per_sample
; }
1347 /* @GenerateCBinding */
1348 void SetOutputBitsPerSample (int value
) { output_bits_per_sample
= value
; }
1350 /* @GenerateCBinding */
1351 int GetOutputBlockAlign () { return output_block_align
; }
1352 /* @GenerateCBinding */
1353 void SetOutputBlockAlign (int value
) { output_block_align
= value
; }
1355 /* @GenerateCBinding */
1356 int GetOutputSampleRate () { return output_sample_rate
; }
1357 /* @GenerateCBinding */
1358 void SetOutputSampleRate (int value
) { output_sample_rate
= value
; }
1360 /* @GenerateCBinding */
1361 int GetOutputChannels () { return output_channels
; }
1362 /* @GenerateCBinding */
1363 void SetOutputChannels (int value
) { output_channels
= value
; }
1365 /* @GenerateCBinding */
1366 int GetOutputBitRate () { return output_bit_rate
; }
1367 /* @GenerateCBinding */
1368 void SetOutputBitRate (int value
) { output_bit_rate
= value
; }
1375 /* @CBindingRequisite */
1376 typedef void (* CloseDemuxerCallback
) (void *instance
);
1377 /* @CBindingRequisite */
1378 typedef void (* GetDiagnosticAsyncCallback
) (void *instance
, int /*MediaStreamSourceDiagnosticKind*/ diagnosticKind
);
1379 /* @CBindingRequisite */
1380 typedef void (* GetFrameAsyncCallback
) (void *instance
, int /*MediaStreamType*/ mediaStreamType
);
1381 /* @CBindingRequisite */
1382 typedef void (* OpenDemuxerAsyncCallback
) (void *instance
, IMediaDemuxer
*demuxer
);
1383 /* @CBindingRequisite */
1384 typedef void (* SeekAsyncCallback
) (void *instance
, guint64 seekToTime
);
1385 /* @CBindingRequisite */
1386 typedef void (* SwitchMediaStreamAsyncCallback
) (void *instance
, IMediaStream
*mediaStreamDescription
);
1388 class ExternalDemuxer
: public IMediaDemuxer
{
1391 pthread_rwlock_t rwlock
;
1392 CloseDemuxerCallback close_demuxer_callback
;
1393 GetDiagnosticAsyncCallback get_diagnostic_async_callback
;
1394 GetFrameAsyncCallback get_sample_async_callback
;
1395 OpenDemuxerAsyncCallback open_demuxer_async_callback
;
1396 SeekAsyncCallback seek_async_callback
;
1397 SwitchMediaStreamAsyncCallback switch_media_stream_async_callback
;
1400 virtual ~ExternalDemuxer ();
1402 virtual void CloseDemuxerInternal ();
1403 virtual void GetDiagnosticAsyncInternal (MediaStreamSourceDiagnosticKind diagnosticsKind
);
1404 virtual void GetFrameAsyncInternal (IMediaStream
*stream
);
1405 virtual void OpenDemuxerAsyncInternal ();
1406 virtual void SeekAsyncInternal (guint64 seekToTime
);
1407 virtual void SwitchMediaStreamAsyncInternal (IMediaStream
*mediaStreamDescription
);
1410 ExternalDemuxer (Media
*media
, void *instance
, CloseDemuxerCallback close_demuxer
,
1411 GetDiagnosticAsyncCallback get_diagnostic
, GetFrameAsyncCallback get_sample
, OpenDemuxerAsyncCallback open_demuxer
,
1412 SeekAsyncCallback seek
, SwitchMediaStreamAsyncCallback switch_media_stream
);
1414 virtual void Dispose ();
1416 /* @GenerateCBinding,GeneratePInvoke */
1417 void SetCanSeek (bool value
);
1419 /* @GenerateCBinding,GeneratePInvoke */
1420 void ClearCallbacks (); /* thread-safe */
1422 /* @GenerateCBinding,GeneratePInvoke */
1423 gint32
AddStream (IMediaStream
*stream
);
1425 virtual const char *GetName () { return "ExternalDemuxer"; }
1432 /* @CBindingRequisite */
1433 typedef void (* ExternalDecoder_DecodeFrameAsyncCallback
) (void *instance
, MediaFrame
*frame
);
1434 /* @CBindingRequisite */
1435 typedef void (* ExternalDecoder_OpenDecoderAsyncCallback
) (void *instance
);
1436 /* @CBindingRequisite */
1437 typedef void (* ExternalDecoder_CleanupCallback
) (void *instance
, MediaFrame
*frame
);
1438 /* @CBindingRequisite */
1439 typedef void (* ExternalDecoder_CleanStateCallback
) (void *instance
);
1440 /* @CBindingRequisite */
1441 typedef bool (* ExternalDecoder_HasDelayedFrameCallback
) (void *instance
);
1442 /* @CBindingRequisite */
1443 typedef void (* ExternalDecoder_DisposeCallback
) (void *instance
);
1444 /* @CBindingRequisite */
1445 typedef void (* ExternalDecoder_DtorCallback
) (void *instance
);
1447 class ExternalDecoder
: public IMediaDecoder
{
1451 ExternalDecoder_DecodeFrameAsyncCallback decode_frame_async
;
1452 ExternalDecoder_OpenDecoderAsyncCallback open_decoder_async
;
1453 ExternalDecoder_CleanupCallback cleanup
;
1454 ExternalDecoder_CleanStateCallback clean_state
;
1455 ExternalDecoder_HasDelayedFrameCallback has_delayed_frame
;
1456 ExternalDecoder_DisposeCallback dispose
;
1457 ExternalDecoder_DtorCallback dtor
;
1460 virtual ~ExternalDecoder ();
1462 virtual void DecodeFrameAsyncInternal (MediaFrame
*frame
);
1463 virtual void OpenDecoderAsyncInternal ();
1465 virtual void InputEnded ();
1467 /* @GenerateCBinding */
1468 ExternalDecoder (Media
*media
, IMediaStream
*stream
, void *instance
, const char *name
,
1469 ExternalDecoder_DecodeFrameAsyncCallback decode_frame_async
,
1470 ExternalDecoder_OpenDecoderAsyncCallback open_decoder_async
,
1471 ExternalDecoder_CleanupCallback cleanup
,
1472 ExternalDecoder_CleanStateCallback clean_state
,
1473 ExternalDecoder_HasDelayedFrameCallback has_delayed_frame
,
1474 ExternalDecoder_DisposeCallback dispose
,
1475 ExternalDecoder_DtorCallback dtor
);
1477 virtual void Dispose ();
1480 // If MediaFrame->decoder_specific_data is non-NULL, this method is called in ~MediaFrame.
1481 virtual void Cleanup (MediaFrame
*frame
);
1482 virtual void CleanState ();
1483 virtual bool HasDelayedFrame ();
1485 virtual const char *GetName () { return name
; }
1489 * ExternalDecoderInfo
1492 /* @CBindingRequisite */
1493 typedef bool (* ExternalDecoderInfo_SupportsCallback
) (void *instance
, const char *codec
);
1494 /* @CBindingRequisite */
1495 typedef IMediaDecoder
* (* ExternalDecoderInfo_Create
) (void *instance
, Media
*media
, IMediaStream
*stream
);
1496 /* @CBindingRequisite */
1497 typedef void (* ExternalDecoderInfo_dtor
) (void *instance
);
1499 class ExternalDecoderInfo
: public DecoderInfo
{
1503 ExternalDecoderInfo_SupportsCallback supports
;
1504 ExternalDecoderInfo_Create create
;
1505 ExternalDecoderInfo_dtor dtor
;
1508 /* @GenerateCBinding */
1509 ExternalDecoderInfo (void *instance
, const char *name
, ExternalDecoderInfo_SupportsCallback supports
, ExternalDecoderInfo_Create create
, ExternalDecoderInfo_dtor dtor
);
1511 virtual bool Supports (const char *codec
);
1512 virtual IMediaDecoder
*Create (Media
*media
, IMediaStream
*stream
);
1514 virtual ~ExternalDecoderInfo ();
1516 virtual const char *GetName () { return name
; }
1522 class ASXDemuxer
: public IMediaDemuxer
{
1527 virtual ~ASXDemuxer ();
1528 virtual MediaResult
SeekInternal (guint64 pts
) { return MEDIA_FAIL
; }
1530 virtual void GetFrameAsyncInternal (IMediaStream
*stream
) { ReportErrorOccurred ("GetFrameAsync isn't supported for ASXDemuxer"); }
1531 virtual void OpenDemuxerAsyncInternal ();
1532 virtual void SeekAsyncInternal (guint64 seekToTime
) {}
1533 virtual void SwitchMediaStreamAsyncInternal (IMediaStream
*stream
) {}
1536 ASXDemuxer (Media
*media
, IMediaSource
*source
);
1537 virtual void Dispose ();
1539 virtual bool IsPlaylist () { return true; }
1540 virtual Playlist
*GetPlaylist () { return playlist
; }
1541 virtual const char *GetName () { return "ASXDemuxer"; }
1544 class ASXDemuxerInfo
: public DemuxerInfo
{
1546 virtual MediaResult
Supports (IMediaSource
*source
);
1547 virtual IMediaDemuxer
*Create (Media
*media
, IMediaSource
*source
);
1548 virtual const char *GetName () { return "ASXDemuxer"; }
1551 class MarkerStream
: public IMediaStream
{
1553 MediaMarkerFoundClosure
*closure
;
1555 List list
; // a list of markers found while there were no callback.
1558 virtual ~MarkerStream () {}
1561 MarkerStream (Media
*media
);
1562 virtual void Dispose ();
1564 virtual MediaStreamType
GetType () { return MediaTypeMarker
; }
1566 void SetCallback (MediaMarkerFoundClosure
*closure
);
1568 // Since the markers are taking the wrong way through the pipeline
1569 // (it's the pipeline who is pushing the markers up to the consumer,
1570 // not the consumer reading new markers), this works in the following way:
1571 // The demuxer reaches a marker somehow, creates a MediaFrame with the marker data and calls MarkerFound on the MarkerStream.
1572 // The MarkerStream calls the decoder to decode the frame.
1573 // The decoder must create an instance of MediaMarker and store it in the frame's buffer.
1574 // The MarkerStream then calls the closure with the MediaMarker.
1576 // - The stream (in MarkerFound) frees the MediaMarker.
1577 // - The demuxer frees the MediaFrame, and the original frame buffer (before decoding).
1578 void MarkerFound (MediaFrame
*frame
);
1580 virtual void FrameEnqueued ();
1581 MediaMarker
*Pop ();
1584 class PassThroughDecoder
: public IMediaDecoder
{
1586 virtual ~PassThroughDecoder () {}
1587 virtual void DecodeFrameAsyncInternal (MediaFrame
*frame
);
1588 virtual void OpenDecoderAsyncInternal ();
1591 PassThroughDecoder (Media
*media
, IMediaStream
*stream
);
1592 virtual void Dispose ();
1594 virtual const char *GetName () { return "PassThroughDecoder"; }
1597 class PassThroughDecoderInfo
: public DecoderInfo
{
1599 virtual bool Supports (const char *codec
);
1600 virtual IMediaDecoder
*Create (Media
*media
, IMediaStream
*stream
)
1602 return new PassThroughDecoder (media
, stream
);
1604 virtual const char *GetName () { return "PassThroughDecoder"; }
1607 class NullDecoder
: public IMediaDecoder
{
1616 MediaResult
DecodeVideoFrame (MediaFrame
*frame
);
1617 MediaResult
DecodeAudioFrame (MediaFrame
*frame
);
1618 MediaResult
OpenAudio ();
1619 MediaResult
OpenVideo ();
1622 virtual ~NullDecoder () {}
1623 virtual void DecodeFrameAsyncInternal (MediaFrame
*frame
);
1624 virtual void OpenDecoderAsyncInternal ();
1627 NullDecoder (Media
*media
, IMediaStream
*stream
);
1628 virtual void Dispose ();
1630 virtual const char *GetName () { return "NullDecoder"; }
1633 class NullDecoderInfo
: public DecoderInfo
{
1635 virtual bool Supports (const char *codec
);
1637 virtual IMediaDecoder
*Create (Media
*media
, IMediaStream
*stream
)
1639 return new NullDecoder (media
, stream
);
1641 virtual const char *GetName () { return "NullDecoder"; }