update copyright date
[gnash.git] / libcore / asobj / NetStream_as.h
blobe3118f05b08b0d4d86a9dc4b7ab980b0de29e5c3
1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
3 // 2011 Free Software Foundation, Inc
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 #ifndef GNASH_NETSTREAM_H
21 #define GNASH_NETSTREAM_H
24 #ifndef __STDC_CONSTANT_MACROS
25 #define __STDC_CONSTANT_MACROS
26 #endif
28 #include "MediaParser.h"
29 #include "PlayHead.h" // for composition
31 #include "VideoDecoder.h" // for visibility of dtor
32 #include "AudioDecoder.h" // for visibility of dtor
34 #include "VirtualClock.h"
36 #include "Relay.h" // for ActiveRelay inheritance
38 #include <boost/intrusive_ptr.hpp>
39 #include <string>
40 #include <deque>
41 #include <boost/scoped_ptr.hpp>
43 // Forward declarations
44 namespace gnash {
45 class CharacterProxy;
46 class IOChannel;
47 class NetConnection_as;
48 class as_function;
49 class DisplayObject;
50 struct ObjectURI;
51 namespace media {
52 class MediaHandler;
54 namespace sound {
55 class sound_handler;
56 class InputStream;
60 namespace gnash {
62 /// Buffered AudioStreamer
64 /// This class you create passing a sound handler, which will
65 /// be used to implement attach/detach and eventually throw away
66 /// buffers of sound when no sound handler is given.
67 ///
68 /// Then you push samples to a buffer of it and can request attach/detach
69 /// operations. When attached, the sound handler will fetch samples
70 /// from the buffer, in a thread-safe way.
71 ///
72 class BufferedAudioStreamer {
73 public:
75 /// @param handler
76 /// %Sound handler to use for attach/detach
77 ///
78 BufferedAudioStreamer(sound::sound_handler* handler);
80 /// A buffer with a cursor state
82 /// @todo Make private, have ::push take a simpler
83 /// form (Buffer?)
84 ///
85 class CursoredBuffer
87 public:
88 CursoredBuffer()
90 m_size(0),
91 m_data(NULL),
92 m_ptr(NULL)
95 ~CursoredBuffer()
97 delete [] m_data;
100 /// Number of samples left in buffer starting from cursor
101 boost::uint32_t m_size;
103 /// Actual data
105 /// The data must be allocated with new []
106 /// as will be delete []'d by the dtor
107 boost::uint8_t* m_data;
109 /// Cursor into the data
110 boost::uint8_t* m_ptr;
113 typedef std::deque<CursoredBuffer*> AudioQueue;
115 // Delete all samples in the audio queue.
116 void cleanAudioQueue();
118 sound::sound_handler* _soundHandler;
120 /// This is where audio frames are pushed by ::advance
121 /// and consumed by sound_handler callback (audio_streamer)
122 AudioQueue _audioQueue;
124 /// Number of bytes in the audio queue, protected by _audioQueueMutex
125 size_t _audioQueueSize;
127 /// The queue needs to be protected as sound_handler callback
128 /// is invoked by a separate thread (dunno if it makes sense actually)
129 boost::mutex _audioQueueMutex;
131 // Id of an attached audio streamer, 0 if none
132 sound::InputStream* _auxStreamer;
134 /// Attach the aux streamer.
136 /// On success, _auxStreamerAttached will be set to true.
137 /// Won't attach again if already attached.
139 void attachAuxStreamer();
141 /// Detach the aux streamer
143 /// _auxStreamerAttached will be set to true.
144 /// Won't detach if not attached.
146 void detachAuxStreamer();
148 /// Fetch samples from the audio queue
149 unsigned int fetch(boost::int16_t* samples, unsigned int nSamples,
150 bool& eof);
152 /// Fetch samples from the audio queue
153 static unsigned int fetchWrapper(void* owner, boost::int16_t* samples,
154 unsigned int nSamples, bool& eof);
156 /// Push a buffer to the audio queue
158 /// @param audio
159 /// Samples buffer, ownership transferred.
161 /// @todo: take something simpler (SimpleBuffer?)
163 void push(CursoredBuffer* audio);
167 // -----------------------------------------------------------------
169 /// NetStream_as ActionScript class
171 /// This class is responsible for handlign external
172 /// media files. Provides interfaces for playback control.
174 class NetStream_as : public ActiveRelay
177 public:
179 enum PauseMode {
180 pauseModeToggle = -1,
181 pauseModePause = 0,
182 pauseModeUnPause = 1
185 NetStream_as(as_object* owner);
187 ~NetStream_as();
189 PlayHead::PlaybackStatus playbackState() const {
190 return _playHead.getState();
193 /// Get the real height of the video in pixels if the decoder exists.
195 /// @return the height of the video in pixels or 0 if no decoder exists.
196 /// The width returned from the decoder may also vary, and will
197 /// be 0 until it knows the width.
198 int videoHeight() const;
200 /// Get the real width of the video in pixels if the decoder exists.
202 /// @return the width of the video in pixels or 0 if no decoder exists.
203 /// The width returned from the decoder may also vary, and will
204 /// be 0 until it knows the width.
205 int videoWidth() const;
207 /// Closes the video session and frees all ressources used for decoding
208 /// except the FLV-parser (this might not be correct).
209 void close();
211 /// Make audio controlled by given DisplayObject
212 void setAudioController(DisplayObject* controller);
214 /// Pauses/starts the playback of the media played by the current instance
216 /// @param mode
217 /// Defines what mode to put the instance in.
218 void pause(PauseMode mode);
220 /// Starts the playback of the media
222 /// @param source
223 /// Defines what file to play
225 void play(const std::string& source);
227 /// Seek in the media played by the current instance
229 /// @param pos
230 /// Defines in seconds where to seek to
231 /// @todo take milliseconds !!
233 void seek(boost::uint32_t pos);
235 /// Tells where the playhead currently is
237 /// @return The time in milliseconds of the current playhead position
239 boost::int32_t time();
241 /// Called at the SWF heart-beat. Used to process queued status messages
242 /// and (re)start after a buffering pause. In NetStreamFfmpeg it is also
243 /// used to find the next video frame to be shown, though this might
244 /// change.
245 void update();
247 /// Returns the current framerate in frames per second.
248 double getCurrentFPS() { return 0; }
250 /// Sets the NetConnection needed to access external files
252 /// @param nc
253 /// The NetConnection object to use for network access
255 void setNetCon(NetConnection_as* nc) {
256 _netCon = nc;
259 /// Return true if the NetStream has an associated NetConnection
260 bool isConnected() const { return (_netCon); }
262 /// Specifies the number of milliseconds to buffer before starting
263 /// to display the stream.
265 /// @param time
266 /// The time in milliseconds that should be buffered.
268 void setBufferTime(boost::uint32_t time);
270 /// Returns what the buffer time has been set to. (100 milliseconds
271 /// is default)
273 /// @return The size of the buffer in milliseconds.
275 boost::uint32_t bufferTime() { return m_bufferTime; }
277 /// Returns the number of bytes of the media file that have been buffered.
278 long bytesLoaded();
280 /// Returns the total number of bytes (size) of the media file
282 /// @return the total number of bytes (size) of the media file
284 long bytesTotal();
286 /// Returns the number of millisecond of the media file that is
287 /// buffered and yet to be played
289 /// @return Returns the number of millisecond of the media file that is
290 /// buffered and yet to be played
292 long bufferLength();
294 /// Tells us if there is a new video frame ready
296 /// @return true if a frame is ready, false if not
297 bool newFrameReady();
299 /// Returns the video frame closest to current cursor. See time().
301 /// @return a image containing the video frame, a NULL auto_ptr if
302 /// none were ready
304 std::auto_ptr<image::GnashImage> get_video();
306 /// Register the DisplayObject to invalidate on video updates
307 void setInvalidatedVideo(DisplayObject* ch)
309 _invalidatedVideoCharacter = ch;
312 virtual void markReachableResources() const;
314 /// Callback used by sound_handler to get audio data
316 /// This is a sound_handler::aux_streamer_ptr type.
318 /// It might be invoked by a separate thread (neither main,
319 /// nor decoder thread).
321 static unsigned int audio_streamer(void *udata, boost::int16_t* samples,
322 unsigned int nSamples, bool& eof);
324 protected:
326 /// Status codes used for notifications
327 enum StatusCode {
329 // Internal status, not a valid ActionScript value
330 invalidStatus,
332 /// NetStream.Buffer.Empty (level: status)
333 bufferEmpty,
335 /// NetStream.Buffer.Full (level: status)
336 bufferFull,
338 /// NetStream.Buffer.Flush (level: status)
339 bufferFlush,
341 /// NetStream.Play.Start (level: status)
342 playStart,
344 /// NetStream.Play.Stop (level: status)
345 playStop,
347 /// NetStream.Seek.Notify (level: status)
348 seekNotify,
350 /// NetStream.Play.StreamNotFound (level: error)
351 streamNotFound,
353 /// NetStream.Seek.InvalidTime (level: error)
354 invalidTime
357 NetConnection_as* _netCon;
359 boost::scoped_ptr<CharacterProxy> _audioController;
361 /// Set stream status.
363 /// Valid statuses are:
365 /// Status level:
366 /// - NetStream.Buffer.Empty
367 /// - NetStream.Buffer.Full
368 /// - NetStream.Buffer.Flush
369 /// - NetStream.Play.Start
370 /// - NetStream.Play.Stop
371 /// - NetStream.Seek.Notify
373 /// Error level:
374 /// - NetStream.Play.StreamNotFound
375 /// - NetStream.Seek.InvalidTime
377 /// This method locks the statusMutex during operations
379 void setStatus(StatusCode code);
381 /// \brief
382 /// Call any onStatus event handler passing it
383 /// any queued status change, see _statusQueue
385 /// Will NOT lock the statusMutex itself, rather it will
386 /// iteratively call the popNextPendingStatusNotification()
387 /// private method, which will take care of locking it.
388 /// This is to make sure onStatus handler won't call methods
389 /// possibly trying to obtain the lock again (::play, ::pause, ...)
391 void processStatusNotifications();
393 // The size of the buffer in milliseconds
394 boost::uint32_t m_bufferTime;
396 // Are a new frame ready to be returned?
397 volatile bool m_newFrameReady;
399 // Mutex to insure we don't corrupt the image
400 boost::mutex image_mutex;
402 // The image/videoframe which is given to the renderer
403 std::auto_ptr<image::GnashImage> m_imageframe;
405 // The video URL
406 std::string url;
408 // The input media parser
409 std::auto_ptr<media::MediaParser> m_parser;
411 // Are we playing a FLV?
412 // The handler which is invoked on status change
413 boost::intrusive_ptr<as_function> _statusHandler;
415 // The position in the inputfile, only used when not playing a FLV
416 long inputPos;
418 /// Unplug the advance timer callback
419 void stopAdvanceTimer();
421 /// Register the advance timer callback
422 void startAdvanceTimer();
424 /// The DisplayObject to invalidate on video updates
425 DisplayObject* _invalidatedVideoCharacter;
427 private:
429 enum DecodingState {
430 DEC_NONE,
431 DEC_STOPPED,
432 DEC_DECODING,
433 DEC_BUFFERING
436 typedef std::pair<std::string, std::string> NetStreamStatus;
438 /// Get 'status' (first) and 'level' (second) strings for given status code
440 /// Any invalid code, out of bound or explicitly invalid (invalidCode)
441 /// returns two empty strings.
443 void getStatusCodeInfo(StatusCode code, NetStreamStatus& info);
445 /// Return a newly allocated information object for the given status
446 as_object* getStatusObject(StatusCode code);
448 /// Initialize video decoder and (if successful) PlayHead consumer
450 /// @param info Video codec information
452 void initVideoDecoder(const media::VideoInfo& info);
454 /// Initialize audio decoder and (if successful) a PlayHead consumer
456 /// @param info Audio codec information
458 void initAudioDecoder(const media::AudioInfo& parser);
460 // Setups the playback
461 bool startPlayback();
463 // Pauses the playhead
465 // Users:
466 // - ::decodeFLVFrame()
467 // - ::pause()
468 // - ::play()
470 void pausePlayback();
472 // Resumes the playback
474 // Users:
475 // - ::av_streamer()
476 // - ::play()
477 // - ::startPlayback()
478 // - ::advance()
480 void unpausePlayback();
482 /// Update the image/videoframe to be returned by next get_video() call.
484 /// Used by update().
486 /// Note that get_video will be called by Video::display(), which
487 /// is usually called right after Video::advance(), so the result
488 /// is that refreshVideoFrame() is called right before
489 /// get_video(). This is important
490 /// to ensure timing is correct..
492 /// @param alsoIfPaused
493 /// If true, video is consumed/refreshed even if playhead is paused.
494 /// By default this is false, but will be used on ::seek (user-reguested)
496 void refreshVideoFrame(bool alsoIfPaused = false);
498 /// Refill audio buffers, so to contain new frames since last run
499 /// and up to current timestamp
500 void refreshAudioBuffer();
502 /// Decode next video frame fetching it MediaParser cursor
504 /// @return 0 on EOF or error, a decoded video otherwise
506 std::auto_ptr<image::GnashImage> decodeNextVideoFrame();
508 /// Decode next audio frame fetching it MediaParser cursor
510 /// @return 0 on EOF or error, a decoded audio frame otherwise
512 BufferedAudioStreamer::CursoredBuffer* decodeNextAudioFrame();
514 /// \brief
515 /// Decode input audio frames with timestamp <= ts
516 /// and push them to the output audio queue
517 void pushDecodedAudioFrames(boost::uint32_t ts);
519 /// Decode input frames up to the one with timestamp <= ts.
521 /// Decoding starts from "next" element in the parser cursor.
523 /// Return 0 if:
524 /// 1. there's no parser active.
525 /// 2. parser cursor is already on last frame.
526 /// 3. next element in cursor has timestamp > tx
527 /// 4. there was an error decoding
529 std::auto_ptr<image::GnashImage> getDecodedVideoFrame(boost::uint32_t ts);
531 DecodingState decodingStatus(DecodingState newstate = DEC_NONE);
533 /// Parse a chunk of input
534 /// Currently blocks, ideally should parse as much
535 /// as possible w/out blocking
536 void parseNextChunk();
538 DecodingState _decoding_state;
540 // Mutex protecting _playback_state and _decoding_state
541 // (not sure a single one is appropriate)
542 boost::mutex _state_mutex;
544 /// Video decoder
545 std::auto_ptr<media::VideoDecoder> _videoDecoder;
547 /// True if video info are known
548 bool _videoInfoKnown;
550 /// Audio decoder
551 std::auto_ptr<media::AudioDecoder> _audioDecoder;
553 /// True if an audio info are known
554 bool _audioInfoKnown;
556 /// Virtual clock used as playback clock source
557 boost::scoped_ptr<InterruptableVirtualClock> _playbackClock;
559 /// Playback control device
560 PlayHead _playHead;
562 // Current sound handler
563 sound::sound_handler* _soundHandler;
565 // Current media handler
566 media::MediaHandler* _mediaHandler;
568 /// Input stream
570 /// This should just be a temporary variable, transferred
571 /// to MediaParser constructor.
573 std::auto_ptr<IOChannel> _inputStream;
575 /// The buffered audio streamer
576 BufferedAudioStreamer _audioStreamer;
578 /// List of status messages to be processed
579 StatusCode _statusCode;
581 /// Mutex protecting _statusQueue
582 boost::mutex statusMutex;
586 void netstream_class_init(as_object& global, const ObjectURI& uri);
588 void registerNetStreamNative(as_object& global);
590 } // gnash namespace
592 #endif