~ubuntu-branches/ubuntu/karmic/gnash/karmic

« back to all changes in this revision

Viewing changes to libcore/asobj/flash/net/NetStream_as.h

  • Committer: Bazaar Package Importer
  • Author(s): Sindhudweep Narayan Sarkar
  • Date: 2009-10-07 00:06:10 UTC
  • mfrom: (1.1.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20091007000610-mj9rwqe774gizn1j
Tags: 0.8.6-0ubuntu1
new upstream release 0.8.6 (LP: #435897)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// 
 
2
//   Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 
3
// 
 
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.
 
8
// 
 
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.
 
13
//
 
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
 
17
 
 
18
 
 
19
#ifndef GNASH_NETSTREAM_H
 
20
#define GNASH_NETSTREAM_H
 
21
 
 
22
#ifdef HAVE_CONFIG_H
 
23
#include "gnashconfig.h"
 
24
#endif
 
25
 
 
26
#ifndef __STDC_CONSTANT_MACROS
 
27
#define __STDC_CONSTANT_MACROS
 
28
#endif
 
29
 
 
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
 
35
 
 
36
#include "VideoDecoder.h" // for visibility of dtor
 
37
#include "AudioDecoder.h" // for visibility of dtor
 
38
 
 
39
#include "VirtualClock.h"
 
40
 
 
41
#include <deque>
 
42
#include <boost/scoped_ptr.hpp>
 
43
 
 
44
// Forward declarations
 
45
namespace gnash {
 
46
    class CharacterProxy;
 
47
    class IOChannel;
 
48
    namespace media {
 
49
        class MediaHandler;
 
50
    }
 
51
    namespace sound {
 
52
        class sound_handler;
 
53
        class InputStream;
 
54
    }
 
55
}
 
56
 
 
57
namespace gnash {
 
58
 
 
59
/// Buffered AudioStreamer
 
60
//
 
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.
 
64
///
 
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.
 
68
///
 
69
class BufferedAudioStreamer {
 
70
public:
 
71
 
 
72
    /// @param handler
 
73
    ///     %Sound handler to use for attach/detach
 
74
    ///
 
75
    BufferedAudioStreamer(sound::sound_handler* handler);
 
76
 
 
77
    /// A buffer with a cursor state
 
78
    //
 
79
    /// @todo Make private, have ::push take a simpler
 
80
    ///       form (Buffer?)
 
81
    ///
 
82
    class CursoredBuffer
 
83
    {
 
84
    public:
 
85
        CursoredBuffer()
 
86
            :
 
87
            m_size(0),
 
88
            m_data(NULL),
 
89
            m_ptr(NULL)
 
90
        {}
 
91
 
 
92
        ~CursoredBuffer()
 
93
        {
 
94
            delete [] m_data;
 
95
        }
 
96
 
 
97
        /// Number of samples left in buffer starting from cursor
 
98
        boost::uint32_t m_size;
 
99
 
 
100
        /// Actual data
 
101
        //
 
102
        /// The data must be allocated with new []
 
103
        /// as will be delete []'d by the dtor
 
104
        boost::uint8_t* m_data;
 
105
 
 
106
        /// Cursor into the data
 
107
        boost::uint8_t* m_ptr;
 
108
    };
 
109
 
 
110
    typedef std::deque<CursoredBuffer*> AudioQueue;
 
111
 
 
112
    // Delete all samples in the audio queue.
 
113
    void cleanAudioQueue();
 
114
 
 
115
    sound::sound_handler* _soundHandler;
 
116
 
 
117
    /// This is where audio frames are pushed by ::advance
 
118
    /// and consumed by sound_handler callback (audio_streamer)
 
119
    AudioQueue _audioQueue;
 
120
 
 
121
    /// Number of bytes in the audio queue, protected by _audioQueueMutex
 
122
    size_t _audioQueueSize;
 
123
 
 
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;
 
127
 
 
128
    // Id of an attached audio streamer, 0 if none
 
129
    sound::InputStream* _auxStreamer;
 
130
 
 
131
    /// Attach the aux streamer.
 
132
    //
 
133
    /// On success, _auxStreamerAttached will be set to true.
 
134
    /// Won't attach again if already attached.
 
135
    ///
 
136
    void attachAuxStreamer();
 
137
 
 
138
    /// Detach the aux streamer
 
139
    //
 
140
    /// _auxStreamerAttached will be set to true.
 
141
    /// Won't detach if not attached.
 
142
    ///
 
143
    void detachAuxStreamer();
 
144
 
 
145
    /// Fetch samples from the audio queue
 
146
    unsigned int fetch(boost::int16_t* samples, unsigned int nSamples,
 
147
                    bool& eof);
 
148
 
 
149
    /// Fetch samples from the audio queue
 
150
    static unsigned int fetchWrapper(void* owner, boost::int16_t* samples,
 
151
                    unsigned int nSamples, bool& eof);
 
152
 
 
153
    /// Push a buffer to the audio queue
 
154
    //
 
155
    /// @param audio
 
156
    ///     Samples buffer, ownership transferred.
 
157
    ///
 
158
    /// @todo: take something simpler (SimpleBuffer?)
 
159
    ///
 
160
    void push(CursoredBuffer* audio);
 
161
 
 
162
};
 
163
 
 
164
// -----------------------------------------------------------------
 
165
 
 
166
/// NetStream_as ActionScript class
 
167
//
 
168
/// This class is responsible for handlign external
 
169
/// media files. Provides interfaces for playback control.
 
170
///
 
171
class NetStream_as : public ActiveRelay
 
172
{
 
173
 
 
174
public:
 
175
 
 
176
    enum PauseMode {
 
177
      pauseModeToggle = -1,
 
178
      pauseModePause = 0,
 
179
      pauseModeUnPause = 1  
 
180
    };
 
181
 
 
182
    NetStream_as(as_object* owner);
 
183
 
 
184
    ~NetStream_as();
 
185
 
 
186
    PlayHead::PlaybackStatus playbackState() const {
 
187
        return _playHead.getState();
 
188
    }
 
189
 
 
190
    /// Get the real height of the video in pixels if the decoder exists.
 
191
    //
 
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;
 
196
 
 
197
    /// Get the real width of the video in pixels if the decoder exists.
 
198
    //
 
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;
 
203
 
 
204
    /// Closes the video session and frees all ressources used for decoding
 
205
    /// except the FLV-parser (this might not be correct).
 
206
    void close();
 
207
 
 
208
    /// Make audio controlled by given DisplayObject
 
209
    void setAudioController(DisplayObject* controller);
 
210
 
 
211
    /// Pauses/starts the playback of the media played by the current instance
 
212
    //
 
213
    /// @param mode
 
214
    /// Defines what mode to put the instance in.
 
215
    void pause(PauseMode mode);
 
216
 
 
217
    /// Starts the playback of the media
 
218
    //
 
219
    /// @param source
 
220
    /// Defines what file to play
 
221
    ///
 
222
    void play(const std::string& source);
 
223
 
 
224
    /// Seek in the media played by the current instance
 
225
    //
 
226
    /// @param pos
 
227
    ///     Defines in seconds where to seek to
 
228
    ///     @todo take milliseconds !!
 
229
    ///
 
230
    void seek(boost::uint32_t pos);
 
231
 
 
232
    /// Tells where the playhead currently is
 
233
    //
 
234
    /// @return The time in milliseconds of the current playhead position
 
235
    ///
 
236
    boost::int32_t time();
 
237
 
 
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
 
241
    /// change.
 
242
    void update();
 
243
    
 
244
    /// Returns the current framerate in frames per second.
 
245
    double getCurrentFPS()  { return 0; }
 
246
 
 
247
    /// Sets the NetConnection needed to access external files
 
248
    //
 
249
    /// @param nc
 
250
    ///     The NetConnection object to use for network access
 
251
    ///
 
252
    void setNetCon(NetConnection_as* nc) {
 
253
        _netCon = nc;
 
254
    }
 
255
 
 
256
    /// Return true if the NetStream has an associated NetConnection
 
257
    bool isConnected() const { return (_netCon); }
 
258
 
 
259
    /// Specifies the number of milliseconds to buffer before starting
 
260
    /// to display the stream.
 
261
    //
 
262
    /// @param time
 
263
    /// The time in milliseconds that should be buffered.
 
264
    ///
 
265
    void setBufferTime(boost::uint32_t time);
 
266
 
 
267
    /// Returns what the buffer time has been set to. (100 milliseconds
 
268
    /// is default)
 
269
    //
 
270
    /// @return The size of the buffer in milliseconds.
 
271
    ///
 
272
    boost::uint32_t bufferTime() { return m_bufferTime; }
 
273
 
 
274
    /// Returns the number of bytes of the media file that have been buffered.
 
275
    long bytesLoaded();
 
276
 
 
277
    /// Returns the total number of bytes (size) of the media file
 
278
    //
 
279
    /// @return the total number of bytes (size) of the media file
 
280
    ///
 
281
    long bytesTotal();
 
282
 
 
283
    /// Returns the number of millisecond of the media file that is
 
284
    /// buffered and yet to be played
 
285
    //
 
286
    /// @return Returns the number of millisecond of the media file that is 
 
287
    /// buffered and yet to be played
 
288
    ///
 
289
    long bufferLength();
 
290
 
 
291
    /// Tells us if there is a new video frame ready
 
292
    //
 
293
    /// @return true if a frame is ready, false if not
 
294
    bool newFrameReady();
 
295
 
 
296
    /// Returns the video frame closest to current cursor. See time().
 
297
    //
 
298
    /// @return a image containing the video frame, a NULL auto_ptr if
 
299
    /// none were ready
 
300
    ///
 
301
    std::auto_ptr<GnashImage> get_video();
 
302
    
 
303
    /// Register the DisplayObject to invalidate on video updates
 
304
    void setInvalidatedVideo(DisplayObject* ch)
 
305
    {
 
306
        _invalidatedVideoCharacter = ch;
 
307
    }
 
308
 
 
309
    virtual void markReachableResources() const;
 
310
 
 
311
    /// Callback used by sound_handler to get audio data
 
312
    //
 
313
    /// This is a sound_handler::aux_streamer_ptr type.
 
314
    ///
 
315
    /// It might be invoked by a separate thread (neither main,
 
316
    /// nor decoder thread).
 
317
    ///
 
318
    static unsigned int audio_streamer(void *udata, boost::int16_t* samples,
 
319
            unsigned int nSamples, bool& eof);
 
320
 
 
321
protected:
 
322
    
 
323
    /// Status codes used for notifications
 
324
    enum StatusCode {
 
325
    
 
326
        // Internal status, not a valid ActionScript value
 
327
        invalidStatus,
 
328
 
 
329
        /// NetStream.Buffer.Empty (level: status)
 
330
        bufferEmpty,
 
331
 
 
332
        /// NetStream.Buffer.Full (level: status)
 
333
        bufferFull,
 
334
 
 
335
        /// NetStream.Buffer.Flush (level: status)
 
336
        bufferFlush,
 
337
 
 
338
        /// NetStream.Play.Start (level: status)
 
339
        playStart,
 
340
 
 
341
        /// NetStream.Play.Stop  (level: status)
 
342
        playStop,
 
343
 
 
344
        /// NetStream.Seek.Notify  (level: status)
 
345
        seekNotify,
 
346
 
 
347
        /// NetStream.Play.StreamNotFound (level: error)
 
348
        streamNotFound,
 
349
 
 
350
        /// NetStream.Seek.InvalidTime (level: error)
 
351
        invalidTime
 
352
    };
 
353
 
 
354
    NetConnection_as* _netCon;
 
355
 
 
356
    boost::scoped_ptr<CharacterProxy> _audioController;
 
357
 
 
358
    /// Set stream status.
 
359
    //
 
360
    /// Valid statuses are:
 
361
    ///
 
362
    /// Status level:
 
363
    ///  - NetStream.Buffer.Empty
 
364
    ///  - NetStream.Buffer.Full
 
365
    ///  - NetStream.Buffer.Flush
 
366
    ///  - NetStream.Play.Start
 
367
    ///  - NetStream.Play.Stop 
 
368
    ///  - NetStream.Seek.Notify 
 
369
    ///
 
370
    /// Error level:
 
371
    ///  - NetStream.Play.StreamNotFound
 
372
    ///  - NetStream.Seek.InvalidTime
 
373
    ///
 
374
    /// This method locks the statusMutex during operations
 
375
    ///
 
376
    void setStatus(StatusCode code);
 
377
 
 
378
    /// \brief
 
379
    /// Call any onStatus event handler passing it
 
380
    /// any queued status change, see _statusQueue
 
381
    //
 
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, ...)
 
387
    ///
 
388
    void processStatusNotifications();
 
389
    
 
390
    
 
391
    void processNotify(const std::string& funcname, as_object* metadata_obj);
 
392
 
 
393
    // The size of the buffer in milliseconds
 
394
    boost::uint32_t m_bufferTime;
 
395
 
 
396
    // Are a new frame ready to be returned?
 
397
    volatile bool m_newFrameReady;
 
398
 
 
399
    // Mutex to insure we don't corrupt the image
 
400
    boost::mutex image_mutex;
 
401
 
 
402
    // The image/videoframe which is given to the renderer
 
403
    std::auto_ptr<GnashImage> m_imageframe;
 
404
 
 
405
    // The video URL
 
406
    std::string url;
 
407
 
 
408
    // The input media parser
 
409
    std::auto_ptr<media::MediaParser> m_parser;
 
410
 
 
411
    // Are we playing a FLV?
 
412
    // The handler which is invoked on status change
 
413
    boost::intrusive_ptr<as_function> _statusHandler;
 
414
 
 
415
    // The position in the inputfile, only used when not playing a FLV
 
416
    long inputPos;
 
417
 
 
418
    /// Unplug the advance timer callback
 
419
    void stopAdvanceTimer();
 
420
 
 
421
    /// Register the advance timer callback
 
422
    void startAdvanceTimer();
 
423
 
 
424
    /// The DisplayObject to invalidate on video updates
 
425
    DisplayObject* _invalidatedVideoCharacter;
 
426
 
 
427
private:
 
428
 
 
429
    enum DecodingState {
 
430
        DEC_NONE,
 
431
        DEC_STOPPED,
 
432
        DEC_DECODING,
 
433
        DEC_BUFFERING
 
434
    };
 
435
 
 
436
    typedef std::pair<std::string, std::string> NetStreamStatus;
 
437
 
 
438
    /// Get 'status' (first) and 'level' (second) strings for given status code
 
439
    //
 
440
    /// Any invalid code, out of bound or explicitly invalid (invalidCode) 
 
441
    /// returns two empty strings.
 
442
    ///
 
443
    void getStatusCodeInfo(StatusCode code, NetStreamStatus& info);
 
444
 
 
445
    /// Return a newly allocated information object for the given status
 
446
    as_object* getStatusObject(StatusCode code);
 
447
 
 
448
    /// Initialize video decoder and (if successful) PlayHead consumer 
 
449
    //
 
450
    /// @param info Video codec information
 
451
    ///
 
452
    void initVideoDecoder(const media::VideoInfo& info);
 
453
 
 
454
    /// Initialize audio decoder and (if successful) a PlayHead consumer 
 
455
    //
 
456
    /// @param info Audio codec information
 
457
    ///
 
458
    void initAudioDecoder(const media::AudioInfo& parser);
 
459
 
 
460
    // Setups the playback
 
461
    bool startPlayback();
 
462
 
 
463
    // Pauses the playhead 
 
464
    //
 
465
    // Users:
 
466
    //  - ::decodeFLVFrame() 
 
467
    //  - ::pause() 
 
468
    //  - ::play() 
 
469
    //
 
470
    void pausePlayback();
 
471
 
 
472
    // Resumes the playback 
 
473
    //
 
474
    // Users:
 
475
    //  - ::av_streamer() 
 
476
    //  - ::play() 
 
477
    //  - ::startPlayback() 
 
478
    //  - ::advance() 
 
479
    //
 
480
    void unpausePlayback();
 
481
 
 
482
    /// Update the image/videoframe to be returned by next get_video() call.
 
483
    //
 
484
    /// Used by update().
 
485
    ///
 
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..
 
491
    ///
 
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)
 
495
    ///
 
496
    void refreshVideoFrame(bool alsoIfPaused = false);
 
497
 
 
498
    /// Refill audio buffers, so to contain new frames since last run
 
499
    /// and up to current timestamp
 
500
    void refreshAudioBuffer();
 
501
 
 
502
    /// Used to decode and push the next available (non-FLV) frame to
 
503
    /// the audio or video queue
 
504
    bool decodeMediaFrame();
 
505
 
 
506
    /// Decode next video frame fetching it MediaParser cursor
 
507
    //
 
508
    /// @return 0 on EOF or error, a decoded video otherwise
 
509
    ///
 
510
    std::auto_ptr<GnashImage> decodeNextVideoFrame();
 
511
 
 
512
    /// Decode next audio frame fetching it MediaParser cursor
 
513
    //
 
514
    /// @return 0 on EOF or error, a decoded audio frame otherwise
 
515
    ///
 
516
    BufferedAudioStreamer::CursoredBuffer* decodeNextAudioFrame();
 
517
 
 
518
    /// \brief
 
519
    /// Decode input audio frames with timestamp <= ts
 
520
    /// and push them to the output audio queue
 
521
    void pushDecodedAudioFrames(boost::uint32_t ts);
 
522
 
 
523
    /// Decode input frames up to the one with timestamp <= ts.
 
524
    //
 
525
    /// Decoding starts from "next" element in the parser cursor.
 
526
    ///
 
527
    /// Return 0 if:
 
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
 
532
    ///
 
533
    std::auto_ptr<GnashImage> getDecodedVideoFrame(boost::uint32_t ts);
 
534
 
 
535
    DecodingState decodingStatus(DecodingState newstate = DEC_NONE);
 
536
 
 
537
    /// Parse a chunk of input
 
538
    /// Currently blocks, ideally should parse as much
 
539
    /// as possible w/out blocking
 
540
    void parseNextChunk();
 
541
 
 
542
    DecodingState _decoding_state;
 
543
 
 
544
    // Mutex protecting _playback_state and _decoding_state
 
545
    // (not sure a single one is appropriate)
 
546
    boost::mutex _state_mutex;
 
547
    
 
548
    /// Video decoder
 
549
    std::auto_ptr<media::VideoDecoder> _videoDecoder;
 
550
 
 
551
    /// True if video info are known
 
552
    bool _videoInfoKnown;
 
553
 
 
554
    /// Audio decoder
 
555
    std::auto_ptr<media::AudioDecoder> _audioDecoder;
 
556
 
 
557
    /// True if an audio info are known
 
558
    bool _audioInfoKnown;
 
559
 
 
560
    /// Virtual clock used as playback clock source
 
561
    boost::scoped_ptr<InterruptableVirtualClock> _playbackClock;
 
562
 
 
563
    /// Playback control device 
 
564
    PlayHead _playHead;
 
565
 
 
566
    // Current sound handler
 
567
    sound::sound_handler* _soundHandler;
 
568
 
 
569
    // Current media handler
 
570
    media::MediaHandler* _mediaHandler;
 
571
 
 
572
    /// Input stream
 
573
    //
 
574
    /// This should just be a temporary variable, transferred
 
575
    /// to MediaParser constructor.
 
576
    ///
 
577
    std::auto_ptr<IOChannel> _inputStream;
 
578
 
 
579
    /// The buffered audio streamer
 
580
    BufferedAudioStreamer _audioStreamer;
 
581
 
 
582
    /// List of status messages to be processed
 
583
    StatusCode _statusCode;
 
584
 
 
585
    /// Mutex protecting _statusQueue
 
586
    boost::mutex statusMutex;
 
587
 
 
588
};
 
589
 
 
590
void netstream_class_init(as_object& global, const ObjectURI& uri);
 
591
 
 
592
void registerNetStreamNative(as_object& global);
 
593
 
 
594
} // gnash namespace
 
595
 
 
596
#endif
 
597