2
// Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
4
// This program is free software; you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation; either version 3 of the License, or
7
// (at your option) any later version.
9
// This program is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
// GNU General Public License for more details.
14
// You should have received a copy of the GNU General Public License
15
// along with this program; if not, write to the Free Software
16
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
#ifndef GNASH_NETSTREAM_H
20
#define GNASH_NETSTREAM_H
23
#include "gnashconfig.h"
26
#ifndef __STDC_CONSTANT_MACROS
27
#define __STDC_CONSTANT_MACROS
30
#include "smart_ptr.h" // GNASH_USE_GC
31
#include "MediaParser.h"
32
#include "as_function.h" // for visibility of destructor by intrusive_ptr
33
#include "NetConnection_as.h"
34
#include "PlayHead.h" // for composition
36
#include "VideoDecoder.h" // for visibility of dtor
37
#include "AudioDecoder.h" // for visibility of dtor
39
#include "VirtualClock.h"
42
#include <boost/scoped_ptr.hpp>
44
// Forward declarations
59
/// Buffered AudioStreamer
61
/// This class you create passing a sound handler, which will
62
/// be used to implement attach/detach and eventually throw away
63
/// buffers of sound when no sound handler is given.
65
/// Then you push samples to a buffer of it and can request attach/detach
66
/// operations. When attached, the sound handler will fetch samples
67
/// from the buffer, in a thread-safe way.
69
class BufferedAudioStreamer {
73
/// %Sound handler to use for attach/detach
75
BufferedAudioStreamer(sound::sound_handler* handler);
77
/// A buffer with a cursor state
79
/// @todo Make private, have ::push take a simpler
97
/// Number of samples left in buffer starting from cursor
98
boost::uint32_t m_size;
102
/// The data must be allocated with new []
103
/// as will be delete []'d by the dtor
104
boost::uint8_t* m_data;
106
/// Cursor into the data
107
boost::uint8_t* m_ptr;
110
typedef std::deque<CursoredBuffer*> AudioQueue;
112
// Delete all samples in the audio queue.
113
void cleanAudioQueue();
115
sound::sound_handler* _soundHandler;
117
/// This is where audio frames are pushed by ::advance
118
/// and consumed by sound_handler callback (audio_streamer)
119
AudioQueue _audioQueue;
121
/// Number of bytes in the audio queue, protected by _audioQueueMutex
122
size_t _audioQueueSize;
124
/// The queue needs to be protected as sound_handler callback
125
/// is invoked by a separate thread (dunno if it makes sense actually)
126
boost::mutex _audioQueueMutex;
128
// Id of an attached audio streamer, 0 if none
129
sound::InputStream* _auxStreamer;
131
/// Attach the aux streamer.
133
/// On success, _auxStreamerAttached will be set to true.
134
/// Won't attach again if already attached.
136
void attachAuxStreamer();
138
/// Detach the aux streamer
140
/// _auxStreamerAttached will be set to true.
141
/// Won't detach if not attached.
143
void detachAuxStreamer();
145
/// Fetch samples from the audio queue
146
unsigned int fetch(boost::int16_t* samples, unsigned int nSamples,
149
/// Fetch samples from the audio queue
150
static unsigned int fetchWrapper(void* owner, boost::int16_t* samples,
151
unsigned int nSamples, bool& eof);
153
/// Push a buffer to the audio queue
156
/// Samples buffer, ownership transferred.
158
/// @todo: take something simpler (SimpleBuffer?)
160
void push(CursoredBuffer* audio);
164
// -----------------------------------------------------------------
166
/// NetStream_as ActionScript class
168
/// This class is responsible for handlign external
169
/// media files. Provides interfaces for playback control.
171
class NetStream_as : public ActiveRelay
177
pauseModeToggle = -1,
182
NetStream_as(as_object* owner);
186
PlayHead::PlaybackStatus playbackState() const {
187
return _playHead.getState();
190
/// Get the real height of the video in pixels if the decoder exists.
192
/// @return the height of the video in pixels or 0 if no decoder exists.
193
/// The width returned from the decoder may also vary, and will
194
/// be 0 until it knows the width.
195
int videoHeight() const;
197
/// Get the real width of the video in pixels if the decoder exists.
199
/// @return the width of the video in pixels or 0 if no decoder exists.
200
/// The width returned from the decoder may also vary, and will
201
/// be 0 until it knows the width.
202
int videoWidth() const;
204
/// Closes the video session and frees all ressources used for decoding
205
/// except the FLV-parser (this might not be correct).
208
/// Make audio controlled by given DisplayObject
209
void setAudioController(DisplayObject* controller);
211
/// Pauses/starts the playback of the media played by the current instance
214
/// Defines what mode to put the instance in.
215
void pause(PauseMode mode);
217
/// Starts the playback of the media
220
/// Defines what file to play
222
void play(const std::string& source);
224
/// Seek in the media played by the current instance
227
/// Defines in seconds where to seek to
228
/// @todo take milliseconds !!
230
void seek(boost::uint32_t pos);
232
/// Tells where the playhead currently is
234
/// @return The time in milliseconds of the current playhead position
236
boost::int32_t time();
238
/// Called at the SWF heart-beat. Used to process queued status messages
239
/// and (re)start after a buffering pause. In NetStreamFfmpeg it is also
240
/// used to find the next video frame to be shown, though this might
244
/// Returns the current framerate in frames per second.
245
double getCurrentFPS() { return 0; }
247
/// Sets the NetConnection needed to access external files
250
/// The NetConnection object to use for network access
252
void setNetCon(NetConnection_as* nc) {
256
/// Return true if the NetStream has an associated NetConnection
257
bool isConnected() const { return (_netCon); }
259
/// Specifies the number of milliseconds to buffer before starting
260
/// to display the stream.
263
/// The time in milliseconds that should be buffered.
265
void setBufferTime(boost::uint32_t time);
267
/// Returns what the buffer time has been set to. (100 milliseconds
270
/// @return The size of the buffer in milliseconds.
272
boost::uint32_t bufferTime() { return m_bufferTime; }
274
/// Returns the number of bytes of the media file that have been buffered.
277
/// Returns the total number of bytes (size) of the media file
279
/// @return the total number of bytes (size) of the media file
283
/// Returns the number of millisecond of the media file that is
284
/// buffered and yet to be played
286
/// @return Returns the number of millisecond of the media file that is
287
/// buffered and yet to be played
291
/// Tells us if there is a new video frame ready
293
/// @return true if a frame is ready, false if not
294
bool newFrameReady();
296
/// Returns the video frame closest to current cursor. See time().
298
/// @return a image containing the video frame, a NULL auto_ptr if
301
std::auto_ptr<GnashImage> get_video();
303
/// Register the DisplayObject to invalidate on video updates
304
void setInvalidatedVideo(DisplayObject* ch)
306
_invalidatedVideoCharacter = ch;
309
virtual void markReachableResources() const;
311
/// Callback used by sound_handler to get audio data
313
/// This is a sound_handler::aux_streamer_ptr type.
315
/// It might be invoked by a separate thread (neither main,
316
/// nor decoder thread).
318
static unsigned int audio_streamer(void *udata, boost::int16_t* samples,
319
unsigned int nSamples, bool& eof);
323
/// Status codes used for notifications
326
// Internal status, not a valid ActionScript value
329
/// NetStream.Buffer.Empty (level: status)
332
/// NetStream.Buffer.Full (level: status)
335
/// NetStream.Buffer.Flush (level: status)
338
/// NetStream.Play.Start (level: status)
341
/// NetStream.Play.Stop (level: status)
344
/// NetStream.Seek.Notify (level: status)
347
/// NetStream.Play.StreamNotFound (level: error)
350
/// NetStream.Seek.InvalidTime (level: error)
354
NetConnection_as* _netCon;
356
boost::scoped_ptr<CharacterProxy> _audioController;
358
/// Set stream status.
360
/// Valid statuses are:
363
/// - NetStream.Buffer.Empty
364
/// - NetStream.Buffer.Full
365
/// - NetStream.Buffer.Flush
366
/// - NetStream.Play.Start
367
/// - NetStream.Play.Stop
368
/// - NetStream.Seek.Notify
371
/// - NetStream.Play.StreamNotFound
372
/// - NetStream.Seek.InvalidTime
374
/// This method locks the statusMutex during operations
376
void setStatus(StatusCode code);
379
/// Call any onStatus event handler passing it
380
/// any queued status change, see _statusQueue
382
/// Will NOT lock the statusMutex itself, rather it will
383
/// iteratively call the popNextPendingStatusNotification()
384
/// private method, which will take care of locking it.
385
/// This is to make sure onStatus handler won't call methods
386
/// possibly trying to obtain the lock again (::play, ::pause, ...)
388
void processStatusNotifications();
391
void processNotify(const std::string& funcname, as_object* metadata_obj);
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<GnashImage> m_imageframe;
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
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;
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
466
// - ::decodeFLVFrame()
470
void pausePlayback();
472
// Resumes the playback
477
// - ::startPlayback()
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
/// Used to decode and push the next available (non-FLV) frame to
503
/// the audio or video queue
504
bool decodeMediaFrame();
506
/// Decode next video frame fetching it MediaParser cursor
508
/// @return 0 on EOF or error, a decoded video otherwise
510
std::auto_ptr<GnashImage> decodeNextVideoFrame();
512
/// Decode next audio frame fetching it MediaParser cursor
514
/// @return 0 on EOF or error, a decoded audio frame otherwise
516
BufferedAudioStreamer::CursoredBuffer* decodeNextAudioFrame();
519
/// Decode input audio frames with timestamp <= ts
520
/// and push them to the output audio queue
521
void pushDecodedAudioFrames(boost::uint32_t ts);
523
/// Decode input frames up to the one with timestamp <= ts.
525
/// Decoding starts from "next" element in the parser cursor.
528
/// 1. there's no parser active.
529
/// 2. parser cursor is already on last frame.
530
/// 3. next element in cursor has timestamp > tx
531
/// 4. there was an error decoding
533
std::auto_ptr<GnashImage> getDecodedVideoFrame(boost::uint32_t ts);
535
DecodingState decodingStatus(DecodingState newstate = DEC_NONE);
537
/// Parse a chunk of input
538
/// Currently blocks, ideally should parse as much
539
/// as possible w/out blocking
540
void parseNextChunk();
542
DecodingState _decoding_state;
544
// Mutex protecting _playback_state and _decoding_state
545
// (not sure a single one is appropriate)
546
boost::mutex _state_mutex;
549
std::auto_ptr<media::VideoDecoder> _videoDecoder;
551
/// True if video info are known
552
bool _videoInfoKnown;
555
std::auto_ptr<media::AudioDecoder> _audioDecoder;
557
/// True if an audio info are known
558
bool _audioInfoKnown;
560
/// Virtual clock used as playback clock source
561
boost::scoped_ptr<InterruptableVirtualClock> _playbackClock;
563
/// Playback control device
566
// Current sound handler
567
sound::sound_handler* _soundHandler;
569
// Current media handler
570
media::MediaHandler* _mediaHandler;
574
/// This should just be a temporary variable, transferred
575
/// to MediaParser constructor.
577
std::auto_ptr<IOChannel> _inputStream;
579
/// The buffered audio streamer
580
BufferedAudioStreamer _audioStreamer;
582
/// List of status messages to be processed
583
StatusCode _statusCode;
585
/// Mutex protecting _statusQueue
586
boost::mutex statusMutex;
590
void netstream_class_init(as_object& global, const ObjectURI& uri);
592
void registerNetStreamNative(as_object& global);