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

« back to all changes in this revision

Viewing changes to server/asobj/NetStreamFfmpeg.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alexander Sack
  • Date: 2008-10-13 14:29:49 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20081013142949-f6qdvnu4mn05ltdc
Tags: 0.8.4~~bzr9980-0ubuntu1
* new upstream release 0.8.4 (LP: #240325)
* ship new lib usr/lib/gnash/libmozsdk.so.* in mozilla-plugin-gnash
  - update debian/mozilla-plugin-gnash.install
* ship new lib usr/lib/gnash/libgnashnet.so.* in gnash-common
  - update debian/gnash-common.install
* add basic debian/build_head script to build latest CVS head packages.
  - add debian/build_head
* new sound architecture requires build depend on libsdl1.2-dev
  - update debian/control
* head build script now has been completely migrated to bzr (upstream +
  ubuntu)
  - update debian/build_head
* disable kde gui until klash/qt4 has been fixed; keep kde packages as empty
  packages for now.
  - update debian/rules
  - debian/klash.install
  - debian/klash.links
  - debian/klash.manpages
  - debian/konqueror-plugin-gnash.install
* drop libkonq5-dev build dependency accordingly
  - update debian/control
* don't install headers manually anymore. gnash doesnt provide a -dev
  package after all
  - update debian/rules
* update libs installed in gnash-common; libgnashserver-*.so is not available
  anymore (removed); in turn we add the new libgnashcore-*.so
  - update debian/gnash-common.install
* use -Os for optimization and properly pass CXXFLAGS=$(CFLAGS) to configure
  - update debian/rules
* touch firefox .autoreg in postinst of mozilla plugin
  - update debian/mozilla-plugin-gnash.postinst
* link gnash in ubufox plugins directory for the plugin alternative switcher
  - add debian/mozilla-plugin-gnash.links
* suggest ubufox accordingly
  - update debian/control
* add new required build-depends on libgif-dev
  - update debian/control
* add Xb-Npp-Description and Xb-Npp-File as new plugin database meta data
  - update debian/control

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// NetStreamFfmpeg.cpp:  Network streaming for FFMPEG video library, for Gnash.
2
 
// 
3
 
//   Copyright (C) 2005, 2006, 2007, 2008 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.
14
 
//
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
18
 
//
19
 
 
20
 
/* $Id: NetStreamFfmpeg.cpp,v 1.105.2.2 2008/02/27 20:55:02 bjacques Exp $ */
21
 
 
22
 
#ifdef HAVE_CONFIG_H
23
 
#include "gnashconfig.h"
24
 
#endif
25
 
 
26
 
#ifdef USE_FFMPEG
27
 
 
28
 
#include "NetStreamFfmpeg.h"
29
 
#include "log.h"
30
 
#include "fn_call.h"
31
 
#include "NetStream.h"
32
 
#include "render.h"     
33
 
#include "movie_root.h"
34
 
#include "sound_handler.h"
35
 
#include "VideoDecoderFfmpeg.h"
36
 
#include "tu_timer.h" // TODO: use the VirtualClock instead ?
37
 
 
38
 
#include <boost/scoped_array.hpp>
39
 
 
40
 
 
41
 
#if defined(_WIN32) || defined(WIN32)
42
 
# include <windows.h>   // for sleep()
43
 
# define usleep(x) Sleep(x/1000)
44
 
#else
45
 
# include "unistd.h" // for usleep()
46
 
#endif
47
 
 
48
 
/// Define this to add debugging prints for locking
49
 
//#define GNASH_DEBUG_THREADS
50
 
 
51
 
// Define the following macro to have status notification handling debugged
52
 
//#define GNASH_DEBUG_STATUS
53
 
 
54
 
// Used to free data in the AVPackets we create our self
55
 
static void avpacket_destruct(AVPacket* av)
56
 
{
57
 
        delete [] av->data;
58
 
}
59
 
 
60
 
 
61
 
namespace gnash {
62
 
 
63
 
 
64
 
NetStreamFfmpeg::NetStreamFfmpeg():
65
 
        m_video_index(-1),
66
 
        m_audio_index(-1),
67
 
 
68
 
        m_VCodecCtx(NULL),
69
 
        m_ACodecCtx(NULL),
70
 
        m_FormatCtx(NULL),
71
 
        m_Frame(NULL),
72
 
 
73
 
        _decodeThread(NULL),
74
 
 
75
 
        m_last_video_timestamp(0),
76
 
        m_last_audio_timestamp(0),
77
 
        m_current_timestamp(0),
78
 
        m_unqueued_data(NULL),
79
 
        m_time_of_pause(0)
80
 
{
81
 
 
82
 
        ByteIOCxt.buffer = NULL;
83
 
}
84
 
 
85
 
NetStreamFfmpeg::~NetStreamFfmpeg()
86
 
{
87
 
        close();
88
 
}
89
 
 
90
 
 
91
 
void NetStreamFfmpeg::pause( PauseMode mode )
92
 
{
93
 
  switch ( mode ) {
94
 
    case pauseModeToggle:
95
 
                        if ( m_pause ) {
96
 
                          unpausePlayback();
97
 
                        } else {
98
 
                          pausePlayback();
99
 
                        }
100
 
                        break;
101
 
    case pauseModePause:
102
 
                        pausePlayback();
103
 
                        break;
104
 
    case pauseModeUnPause:
105
 
                        unpausePlayback();
106
 
                        break;
107
 
    default:
108
 
                        break;
109
 
  }
110
 
 
111
 
  if ( !m_pause && !m_go ) {
112
 
    setStatus( playStart );
113
 
    m_go = true;
114
 
 
115
 
    _decodeThread = new boost::thread( boost::bind(NetStreamFfmpeg::av_streamer, this) );
116
 
  }
117
 
}
118
 
 
119
 
void NetStreamFfmpeg::close()
120
 
{
121
 
 
122
 
        if (m_go)
123
 
        {
124
 
                // request decoder thread termination
125
 
                m_go = false;
126
 
 
127
 
                // wait till thread is complete before main continues
128
 
                _decodeThread->join();
129
 
 
130
 
                delete _decodeThread;
131
 
 
132
 
        }
133
 
 
134
 
        // When closing gnash before playback is finished, the soundhandler 
135
 
        // seems to be removed before netstream is destroyed.
136
 
        media::sound_handler* s = get_sound_handler();
137
 
        if (s != NULL)
138
 
        {
139
 
                s->detach_aux_streamer(this);
140
 
        }
141
 
 
142
 
        if (m_Frame) av_free(m_Frame);
143
 
        m_Frame = NULL;
144
 
 
145
 
  if ( m_VCodecCtx ) {
146
 
    avcodec_close( m_VCodecCtx );
147
 
  }
148
 
  m_VCodecCtx = NULL;
149
 
 
150
 
  if ( m_ACodecCtx ) {
151
 
    avcodec_close( m_ACodecCtx );
152
 
  }
153
 
  m_ACodecCtx = NULL;
154
 
 
155
 
        if (m_FormatCtx)
156
 
        {
157
 
                m_FormatCtx->iformat->flags = AVFMT_NOFILE;
158
 
                av_close_input_file(m_FormatCtx);
159
 
                m_FormatCtx = NULL;
160
 
        }
161
 
 
162
 
        delete m_imageframe;
163
 
        m_imageframe = NULL;
164
 
        delete m_unqueued_data;
165
 
        m_unqueued_data = NULL;
166
 
 
167
 
        while (m_qvideo.size() > 0)
168
 
        {
169
 
                delete m_qvideo.front();
170
 
                m_qvideo.pop();
171
 
        }
172
 
 
173
 
        while (m_qaudio.size() > 0)
174
 
        {
175
 
                delete m_qaudio.front();
176
 
                m_qaudio.pop();
177
 
        }
178
 
 
179
 
        delete [] ByteIOCxt.buffer;
180
 
 
181
 
}
182
 
 
183
 
// ffmpeg callback function
184
 
int 
185
 
NetStreamFfmpeg::readPacket(void* opaque, boost::uint8_t* buf, int buf_size)
186
 
{
187
 
 
188
 
        NetStreamFfmpeg* ns = static_cast<NetStreamFfmpeg*>(opaque);
189
 
        boost::intrusive_ptr<NetConnection> nc = ns->_netCon;
190
 
 
191
 
        size_t ret = nc->read(static_cast<void*>(buf), buf_size);
192
 
        ns->inputPos += ret;
193
 
        return ret;
194
 
 
195
 
}
196
 
 
197
 
// ffmpeg callback function
198
 
offset_t 
199
 
NetStreamFfmpeg::seekMedia(void *opaque, offset_t offset, int whence)
200
 
{
201
 
 
202
 
        NetStreamFfmpeg* ns = static_cast<NetStreamFfmpeg*>(opaque);
203
 
        boost::intrusive_ptr<NetConnection> nc = ns->_netCon;
204
 
 
205
 
 
206
 
        // Offset is absolute new position in the file
207
 
        if (whence == SEEK_SET)
208
 
        {       
209
 
                nc->seek(offset);
210
 
                ns->inputPos = offset;
211
 
 
212
 
        // New position is offset + old position
213
 
        }
214
 
        else if (whence == SEEK_CUR)
215
 
        {
216
 
                nc->seek(ns->inputPos + offset);
217
 
                ns->inputPos = ns->inputPos + offset;
218
 
 
219
 
        // New position is offset + end of file
220
 
        }
221
 
        else if (whence == SEEK_END)
222
 
        {
223
 
                // This is (most likely) a streamed file, so we can't seek to the end!
224
 
                // Instead we seek to 50.000 bytes... seems to work fine...
225
 
                nc->seek(50000);
226
 
                ns->inputPos = 50000;
227
 
 
228
 
        }
229
 
 
230
 
        return ns->inputPos;
231
 
}
232
 
 
233
 
void
234
 
NetStreamFfmpeg::play(const std::string& c_url)
235
 
{
236
 
 
237
 
        // Is it already playing ?
238
 
        if (m_go)
239
 
        {
240
 
                unpausePlayback(); // will check for m_pause itself..
241
 
                return;
242
 
        }
243
 
 
244
 
        // Does it have an associated NetConnection ?
245
 
        if ( ! _netCon )
246
 
        {
247
 
                IF_VERBOSE_ASCODING_ERRORS(
248
 
                log_aserror(_("No NetConnection associated with this NetStream, won't play"));
249
 
                );
250
 
                return;
251
 
        }
252
 
 
253
 
        if (url.size() == 0) url += c_url;
254
 
        // Remove any "mp3:" prefix. Maybe should use this to mark as audio-only
255
 
        if (url.compare(0, 4, std::string("mp3:")) == 0)
256
 
        {
257
 
                url = url.substr(4);
258
 
        }
259
 
 
260
 
        m_go = true;
261
 
        pausePlayback();
262
 
 
263
 
        // This starts the decoding thread
264
 
        _decodeThread = new boost::thread(boost::bind(NetStreamFfmpeg::av_streamer, this)); 
265
 
 
266
 
        return;
267
 
}
268
 
 
269
 
/// Finds a decoder, allocates a context and initializes it.
270
 
//
271
 
/// @param codec_id the codec ID to find
272
 
/// @return the initialized context, or NULL on failure. The caller is 
273
 
///         responsible for deallocating!
274
 
static AVCodecContext*
275
 
initContext(enum CodecID codec_id)
276
 
{
277
 
 
278
 
        AVCodec* codec = avcodec_find_decoder(codec_id);
279
 
        if (!codec)
280
 
        {
281
 
                log_error(_("libavcodec couldn't find decoder"));
282
 
                return NULL;
283
 
        }
284
 
 
285
 
        AVCodecContext * context = avcodec_alloc_context();
286
 
        if (!context)
287
 
        {
288
 
                log_error(_("libavcodec couldn't allocate context"));
289
 
                return NULL;
290
 
        }
291
 
 
292
 
        int rv = avcodec_open(context, codec);
293
 
        if (rv < 0) 
294
 
        {
295
 
                avcodec_close(context);
296
 
                log_error(_("libavcodec failed to initialize codec"));
297
 
                return NULL;
298
 
        }
299
 
 
300
 
        return context;
301
 
}
302
 
 
303
 
/// Gets video info from the parser and initializes the codec.
304
 
//
305
 
/// @param parser the parser to use to get video information.
306
 
/// @return the initialized context, or NULL on failure. The caller
307
 
///         is responsible for deallocating this pointer.
308
 
static AVCodecContext* 
309
 
initFlvVideo(FLVParser* parser)
310
 
{
311
 
        // Get video info from the parser
312
 
        std::auto_ptr<FLVVideoInfo> videoInfo( parser->getVideoInfo() );
313
 
        if (!videoInfo.get())
314
 
        {
315
 
                return NULL;
316
 
        }
317
 
 
318
 
        enum CodecID codec_id;
319
 
 
320
 
        // Find the decoder and init the parser
321
 
        switch(videoInfo->codec)
322
 
        {
323
 
                case media::VIDEO_CODEC_H263:
324
 
                        codec_id = CODEC_ID_FLV1;
325
 
                        break;
326
 
#ifdef FFMPEG_VP6
327
 
                case media::VIDEO_CODEC_VP6:
328
 
                        codec_id = CODEC_ID_VP6F;
329
 
                        break;
330
 
#endif
331
 
                case media::VIDEO_CODEC_SCREENVIDEO:
332
 
                        codec_id = CODEC_ID_FLASHSV;
333
 
                        break;
334
 
                default:
335
 
                        log_error(_("Unsupported video codec %d"), (int) videoInfo->codec);
336
 
                        return NULL;
337
 
        }
338
 
 
339
 
        return initContext(codec_id);
340
 
}
341
 
 
342
 
 
343
 
/// Like initFlvVideo, but for audio.
344
 
static AVCodecContext*
345
 
initFlvAudio(FLVParser* parser)
346
 
{
347
 
        // Get audio info from the parser
348
 
        std::auto_ptr<FLVAudioInfo> audioInfo( parser->getAudioInfo() );
349
 
        if (!audioInfo.get())
350
 
        {
351
 
                return NULL;
352
 
        }
353
 
 
354
 
        enum CodecID codec_id;
355
 
 
356
 
        switch(audioInfo->codec)
357
 
        {
358
 
                case media::AUDIO_CODEC_RAW:
359
 
                        codec_id = CODEC_ID_PCM_U16LE;
360
 
                        break;
361
 
                case media::AUDIO_CODEC_ADPCM:
362
 
                        codec_id = CODEC_ID_ADPCM_SWF;
363
 
                        break;
364
 
                case media::AUDIO_CODEC_MP3:
365
 
                        codec_id = CODEC_ID_MP3;
366
 
                        break;
367
 
                default:
368
 
                        log_error(_("Unsupported audio codec %d"), (int)audioInfo->codec);
369
 
                        return NULL;
370
 
        }
371
 
 
372
 
        return initContext(codec_id);
373
 
}
374
 
 
375
 
 
376
 
/// Probe the stream and try to figure out what the format is.
377
 
//
378
 
/// @param ns the netstream to use for reading
379
 
/// @return a pointer to the AVInputFormat structure containing
380
 
///         information about the input format, or NULL.
381
 
static AVInputFormat*
382
 
probeStream(NetStreamFfmpeg* ns)
383
 
{
384
 
        boost::scoped_array<boost::uint8_t> buffer(new boost::uint8_t[2048]);
385
 
 
386
 
        // Probe the file to detect the format
387
 
        AVProbeData probe_data;
388
 
        probe_data.filename = "";
389
 
        probe_data.buf = buffer.get();
390
 
        probe_data.buf_size = 2048;
391
 
 
392
 
        if (ns->readPacket(ns, probe_data.buf, probe_data.buf_size) < 1)
393
 
        {
394
 
                log_error(_("Gnash could not read from movie url"));
395
 
                return NULL;
396
 
        }
397
 
 
398
 
        return av_probe_input_format(&probe_data, 1);
399
 
}
400
 
 
401
 
bool
402
 
NetStreamFfmpeg::startPlayback()
403
 
{
404
 
 
405
 
        boost::intrusive_ptr<NetConnection> nc = _netCon;
406
 
        assert(nc);
407
 
 
408
 
        // Pass stuff from/to the NetConnection object.
409
 
        if ( !nc->openConnection(url) )
410
 
        {
411
 
                log_error(_("Gnash could not open movie: %s"), url.c_str());
412
 
                setStatus(streamNotFound);
413
 
                return false;
414
 
        }
415
 
 
416
 
        nc->seek(0);
417
 
        inputPos = 0;
418
 
 
419
 
        // Check if the file is a FLV, in which case we use our own parser
420
 
        char head[4] = {0, 0, 0, 0};
421
 
        if (nc->read(head, 3) < 3)
422
 
        {
423
 
                setStatus(streamNotFound);
424
 
                return false;
425
 
        }
426
 
 
427
 
        nc->seek(0);
428
 
        if (std::string(head) == "FLV")
429
 
        {
430
 
                m_isFLV = true;
431
 
                if (!m_parser.get())
432
 
                {
433
 
                        m_parser = nc->getConnectedParser();
434
 
                        if (! m_parser.get() )
435
 
                        {
436
 
                                setStatus(streamNotFound);
437
 
                                log_error(_("Gnash could not open FLV movie: %s"), url.c_str());
438
 
                                return false;
439
 
                        }
440
 
                }
441
 
 
442
 
                // Init the avdecoder-decoder
443
 
                avcodec_init();
444
 
                avcodec_register_all();
445
 
 
446
 
                m_VCodecCtx = initFlvVideo(m_parser.get());
447
 
                if (!m_VCodecCtx)
448
 
                {
449
 
                        log_error(_("Failed to initialize FLV video codec"));
450
 
                        return false;
451
 
                }
452
 
 
453
 
                m_ACodecCtx = initFlvAudio(m_parser.get());
454
 
                if (!m_ACodecCtx)
455
 
                {
456
 
                        log_error(_("Failed to initialize FLV audio codec"));
457
 
                        return false;
458
 
                }
459
 
 
460
 
                // We just define the indexes here, they're not really used when
461
 
                // the file format is FLV
462
 
                m_video_index = 0;
463
 
                m_audio_index = 1;
464
 
 
465
 
                m_start_onbuffer = true;
466
 
 
467
 
                // Allocate a frame to store the decoded frame in
468
 
                m_Frame = avcodec_alloc_frame();
469
 
                return true;
470
 
        }
471
 
 
472
 
        // This registers all available file formats and codecs 
473
 
        // with the library so they will be used automatically when
474
 
        // a file with the corresponding format/codec is opened
475
 
        // XXX should we call avcodec_init() first?
476
 
        av_register_all();
477
 
 
478
 
        AVInputFormat* inputFmt = probeStream(this);
479
 
        if (!inputFmt)
480
 
        {
481
 
                log_error(_("Couldn't determine stream input format from URL %s"), url.c_str());
482
 
                return false;
483
 
        }
484
 
 
485
 
        // After the format probe, reset to the beginning of the file.
486
 
        nc->seek(0);
487
 
 
488
 
        // Setup the filereader/seeker mechanism. 7th argument (NULL) is the writer function,
489
 
        // which isn't needed.
490
 
        init_put_byte(&ByteIOCxt, new boost::uint8_t[500000], 500000, 0, this, NetStreamFfmpeg::readPacket, NULL, NetStreamFfmpeg::seekMedia);
491
 
        ByteIOCxt.is_streamed = 1;
492
 
 
493
 
        m_FormatCtx = av_alloc_format_context();
494
 
 
495
 
        // Open the stream. the 4th argument is the filename, which we ignore.
496
 
        if(av_open_input_stream(&m_FormatCtx, &ByteIOCxt, "", inputFmt, NULL) < 0)
497
 
        {
498
 
                log_error(_("Couldn't open file '%s' for decoding"), url.c_str());
499
 
                setStatus(streamNotFound);
500
 
                return false;
501
 
        }
502
 
 
503
 
        // Next, we need to retrieve information about the streams contained in the file
504
 
        // This fills the streams field of the AVFormatContext with valid information
505
 
        int ret = av_find_stream_info(m_FormatCtx);
506
 
        if (ret < 0)
507
 
        {
508
 
                log_error(_("Couldn't find stream information from '%s', error code: %d"), url.c_str(), ret);
509
 
                return false;
510
 
        }
511
 
 
512
 
//      m_FormatCtx->pb.eof_reached = 0;
513
 
//      av_read_play(m_FormatCtx);
514
 
 
515
 
        // Find the first video & audio stream
516
 
        m_video_index = -1;
517
 
        m_audio_index = -1;
518
 
        //assert(m_FormatCtx->nb_streams >= 0); useless assert. 
519
 
        for (unsigned int i = 0; i < (unsigned)m_FormatCtx->nb_streams; i++)
520
 
        {
521
 
                AVCodecContext* enc = m_FormatCtx->streams[i]->codec; 
522
 
 
523
 
                switch (enc->codec_type)
524
 
                {
525
 
                        case CODEC_TYPE_AUDIO:
526
 
                                if (m_audio_index < 0)
527
 
                                {
528
 
                                        m_audio_index = i;
529
 
                                        m_audio_stream = m_FormatCtx->streams[i];
530
 
                                }
531
 
                                break;
532
 
 
533
 
                        case CODEC_TYPE_VIDEO:
534
 
                                if (m_video_index < 0)
535
 
                                {
536
 
                                        m_video_index = i;
537
 
                                        m_video_stream = m_FormatCtx->streams[i];
538
 
                                }
539
 
                                break;
540
 
                        default:
541
 
                                break;
542
 
                }
543
 
        }
544
 
 
545
 
        if (m_video_index < 0)
546
 
        {
547
 
                log_error(_("Didn't find a video stream from '%s'"), url.c_str());
548
 
                return false;
549
 
        }
550
 
 
551
 
        // Get a pointer to the codec context for the video stream
552
 
        m_VCodecCtx = m_FormatCtx->streams[m_video_index]->codec;
553
 
 
554
 
        // Find the decoder for the video stream
555
 
        AVCodec* pCodec = avcodec_find_decoder(m_VCodecCtx->codec_id);
556
 
        if (pCodec == NULL)
557
 
        {
558
 
                m_VCodecCtx = NULL;
559
 
                log_error(_("Video decoder %d not found"), 
560
 
                        m_VCodecCtx->codec_id);
561
 
                return false;
562
 
        }
563
 
 
564
 
        // Open codec
565
 
        if (avcodec_open(m_VCodecCtx, pCodec) < 0)
566
 
        {
567
 
                log_error(_("Could not open codec %d"),
568
 
                        m_VCodecCtx->codec_id);
569
 
        }
570
 
 
571
 
        // Allocate a frame to store the decoded frame in
572
 
        m_Frame = avcodec_alloc_frame();
573
 
        
574
 
        // Determine required buffer size and allocate buffer
575
 
        if (m_videoFrameFormat == render::YUV)
576
 
        {
577
 
                m_imageframe = new image::yuv(m_VCodecCtx->width,       m_VCodecCtx->height);
578
 
        }
579
 
        else if (m_videoFrameFormat == render::RGB)
580
 
        {
581
 
                m_imageframe = new image::rgb(m_VCodecCtx->width,       m_VCodecCtx->height);
582
 
        }
583
 
 
584
 
        media::sound_handler* s = get_sound_handler();
585
 
        if (m_audio_index >= 0 && s != NULL)
586
 
        {
587
 
                // Get a pointer to the audio codec context for the video stream
588
 
                m_ACodecCtx = m_FormatCtx->streams[m_audio_index]->codec;
589
 
 
590
 
                // Find the decoder for the audio stream
591
 
                AVCodec* pACodec = avcodec_find_decoder(m_ACodecCtx->codec_id);
592
 
            if (pACodec == NULL)
593
 
                {
594
 
                        log_error(_("No available audio decoder %d to process MPEG file: '%s'"), 
595
 
                                m_ACodecCtx->codec_id, url.c_str());
596
 
                        return false;
597
 
                }
598
 
        
599
 
                // Open codec
600
 
                if (avcodec_open(m_ACodecCtx, pACodec) < 0)
601
 
                {
602
 
                        log_error(_("Could not open audio codec %d for %s"),
603
 
                                m_ACodecCtx->codec_id, url.c_str());
604
 
                        return false;
605
 
                }
606
 
 
607
 
        }
608
 
 
609
 
        unpausePlayback();
610
 
        return true;
611
 
}
612
 
 
613
 
 
614
 
/// Copy RGB data from a source raw_mediadata_t to a destination image::rgb.
615
 
/// @param dst the destination image::rgb, which must already be initialized
616
 
///            with a buffer of size of at least src.m_size.
617
 
/// @param src the source raw_mediadata_t to copy data from. The m_size member
618
 
///            of this structure must be initialized.
619
 
/// @param width the width, in bytes, of a row of video data.
620
 
static void
621
 
rgbcopy(image::rgb* dst, media::raw_mediadata_t* src, int width)
622
 
{
623
 
  assert( src->m_size <= static_cast<boost::uint32_t>(dst->width() * dst->height() * 3) ); 
624
 
 
625
 
  boost::uint8_t* dstptr = dst->data();
626
 
 
627
 
  boost::uint8_t* srcptr = src->m_data;
628
 
  boost::uint8_t* srcend = src->m_data + src->m_size;
629
 
 
630
 
  while (srcptr < srcend) {
631
 
    memcpy(dstptr, srcptr, width);
632
 
    dstptr += dst->pitch();
633
 
    srcptr += width;
634
 
  }
635
 
}
636
 
 
637
 
// decoder thread
638
 
void NetStreamFfmpeg::av_streamer(NetStreamFfmpeg* ns)
639
 
{
640
 
        //GNASH_REPORT_FUNCTION;
641
 
 
642
 
        // This should only happen if close() is called before this thread is ready
643
 
        if (!ns->m_go)
644
 
        {
645
 
                log_debug("av_streamer: !ns->m_go, returning");
646
 
                return;
647
 
        }
648
 
 
649
 
        if (!ns->m_ACodecCtx && !ns->m_VCodecCtx && !ns->m_FormatCtx)
650
 
        {
651
 
                if (!ns->startPlayback())
652
 
                {
653
 
                        log_debug("av_streamer: !ns->startPlayback, returning");
654
 
                        return;
655
 
                }
656
 
        }
657
 
        else
658
 
        {
659
 
                // We need to restart the audio
660
 
                media::sound_handler* s = get_sound_handler();
661
 
                if (s)
662
 
                {
663
 
                        s->attach_aux_streamer(audio_streamer, ns);
664
 
                }
665
 
        }
666
 
 
667
 
        ns->setStatus(playStart);
668
 
 
669
 
        ns->m_last_video_timestamp = 0;
670
 
        ns->m_last_audio_timestamp = 0;
671
 
        ns->m_current_timestamp = 0;
672
 
 
673
 
        ns->m_start_clock = tu_timer::get_ticks();
674
 
 
675
 
        ns->m_unqueued_data = NULL;
676
 
 
677
 
        // Loop while we're playing
678
 
        while (ns->m_go)
679
 
        {
680
 
#ifdef GNASH_DEBUG_THREADS
681
 
                log_debug("Decoding iteration. bufferTime=%lu, bufferLen=%lu", ns->bufferTime(), ns->bufferLength());
682
 
#endif
683
 
 
684
 
                if (ns->m_isFLV)
685
 
                {
686
 
                        // If queues are full then don't bother filling it
687
 
                        if ( ns->m_qvideo.size() < 20 || ns->m_qaudio.size() < 20 ) 
688
 
                        {
689
 
 
690
 
                                // If we have problems with decoding - break
691
 
                                if (!ns->decodeFLVFrame() && ns->m_start_onbuffer == false && ns->m_qvideo.size() == 0 && ns->m_qaudio.size() == 0)
692
 
                                {
693
 
                                        // TODO: do we really want to break here !?
694
 
                                        break;
695
 
                                }
696
 
                        }
697
 
 
698
 
                }
699
 
                else
700
 
                {
701
 
 
702
 
                        // If we have problems with decoding - break
703
 
                        if (ns->decodeMediaFrame() == false && ns->m_start_onbuffer == false && ns->m_qvideo.size() == 0 && ns->m_qaudio.size() == 0)
704
 
                        {
705
 
                                break;
706
 
                        }
707
 
 
708
 
                }
709
 
 
710
 
                usleep(1); // task switch, to avoid 100% CPU
711
 
 
712
 
        }
713
 
 
714
 
#ifdef GNASH_DEBUG_THREADS
715
 
        log_debug("Out of decoding loop");
716
 
#endif
717
 
        ns->m_go = false;
718
 
 
719
 
#ifdef GNASH_DEBUG_STATUS
720
 
        log_debug("Setting playStop status");
721
 
#endif
722
 
        ns->setStatus(playStop);
723
 
}
724
 
 
725
 
// audio callback is running in sound handler thread
726
 
bool NetStreamFfmpeg::audio_streamer(void *owner, boost::uint8_t *stream, int len)
727
 
{
728
 
        //GNASH_REPORT_FUNCTION;
729
 
 
730
 
        NetStreamFfmpeg* ns = static_cast<NetStreamFfmpeg*>(owner);
731
 
 
732
 
        if (!ns->m_go || ns->m_pause)
733
 
        {
734
 
                return false;
735
 
        }
736
 
 
737
 
        while (len > 0 && ns->m_qaudio.size() > 0)
738
 
        {
739
 
                media::raw_mediadata_t* samples = ns->m_qaudio.front();
740
 
 
741
 
                int n = imin(samples->m_size, len);
742
 
                memcpy(stream, samples->m_ptr, n);
743
 
                stream += n;
744
 
                samples->m_ptr += n;
745
 
                samples->m_size -= n;
746
 
                len -= n;
747
 
 
748
 
                ns->m_current_timestamp = samples->m_pts;
749
 
 
750
 
                if (samples->m_size == 0)
751
 
                {
752
 
                        ns->m_qaudio.pop();
753
 
                        delete samples;
754
 
                }
755
 
 
756
 
        }
757
 
        return true;
758
 
}
759
 
 
760
 
bool NetStreamFfmpeg::decodeFLVFrame()
761
 
{
762
 
        FLVFrame* frame = NULL;
763
 
        if ( m_qvideo.size() < m_qaudio.size() ) 
764
 
        {
765
 
                frame = m_parser->nextVideoFrame();
766
 
        } else {
767
 
                frame = m_parser->nextAudioFrame();
768
 
        }
769
 
 
770
 
        if (frame == NULL)
771
 
        {
772
 
                if (_netCon->loadCompleted())
773
 
                {
774
 
#ifdef GNASH_DEBUG_THREADS
775
 
                        log_debug("decodeFLVFrame: load completed, stopping");
776
 
#endif
777
 
                        // Stop!
778
 
                        this->m_go = false;
779
 
                }
780
 
                else
781
 
                {
782
 
                        pausePlayback();
783
 
                        setStatus(bufferEmpty);
784
 
                        m_start_onbuffer = true;
785
 
                }
786
 
                return false;
787
 
        }
788
 
 
789
 
        AVPacket packet;
790
 
 
791
 
        packet.destruct = avpacket_destruct;
792
 
        packet.size = frame->dataSize;
793
 
        packet.data = frame->data;
794
 
        // FIXME: is this the right value for packet.dts?
795
 
        packet.pts = packet.dts = static_cast<boost::int64_t>(frame->timestamp);
796
 
 
797
 
        if (frame->tag == 9)
798
 
        {
799
 
                packet.stream_index = 0;
800
 
                return decodeVideo(&packet);
801
 
        }
802
 
        else
803
 
        {
804
 
                packet.stream_index = 1;
805
 
                return decodeAudio(&packet);
806
 
        }
807
 
 
808
 
}
809
 
 
810
 
 
811
 
bool NetStreamFfmpeg::decodeAudio( AVPacket* packet )
812
 
{
813
 
        if (!m_ACodecCtx) return false;
814
 
 
815
 
        int frame_size;
816
 
        unsigned int bufsize = (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2;
817
 
 
818
 
        boost::uint8_t* ptr = new boost::uint8_t[bufsize];
819
 
#ifdef FFMPEG_AUDIO2
820
 
        frame_size = bufsize;
821
 
        if (avcodec_decode_audio2(m_ACodecCtx, (boost::int16_t*) ptr, &frame_size, packet->data, packet->size) >= 0)
822
 
#else
823
 
        if (avcodec_decode_audio(m_ACodecCtx, (boost::int16_t*) ptr, &frame_size, packet->data, packet->size) >= 0)
824
 
#endif
825
 
        {
826
 
 
827
 
                bool stereo = m_ACodecCtx->channels > 1 ? true : false;
828
 
                int samples = stereo ? frame_size >> 2 : frame_size >> 1;
829
 
                
830
 
                if (_resampler.init(m_ACodecCtx))
831
 
                {
832
 
                        // Resampling is needed.
833
 
                        
834
 
                        boost::uint8_t* output = new boost::uint8_t[bufsize];
835
 
                        
836
 
                        samples = _resampler.resample(reinterpret_cast<boost::int16_t*>(ptr), 
837
 
                                                         reinterpret_cast<boost::int16_t*>(output), 
838
 
                                                         samples);
839
 
                        delete [] ptr;
840
 
                        ptr = reinterpret_cast<boost::uint8_t*>(output);
841
 
                }
842
 
                
843
 
                media::raw_mediadata_t* raw = new media::raw_mediadata_t();
844
 
                
845
 
                raw->m_data = ptr;
846
 
                raw->m_ptr = raw->m_data;
847
 
                raw->m_size = samples * 2 * 2; // 2 for stereo and 2 for samplesize = 2 bytes
848
 
                raw->m_stream_index = m_audio_index;
849
 
 
850
 
                // set presentation timestamp
851
 
                if (packet->dts != static_cast<signed long>(AV_NOPTS_VALUE))
852
 
                {
853
 
                        if (!m_isFLV) raw->m_pts = static_cast<boost::uint32_t>(as_double(m_audio_stream->time_base) * packet->dts * 1000.0);
854
 
                        else raw->m_pts = static_cast<boost::uint32_t>((as_double(m_ACodecCtx->time_base) * packet->dts) * 1000.0);
855
 
                }
856
 
 
857
 
                if (raw->m_pts != 0)
858
 
                {       
859
 
                        // update audio clock with pts, if present
860
 
                        m_last_audio_timestamp = raw->m_pts;
861
 
                }
862
 
                else
863
 
                {
864
 
                        raw->m_pts = m_last_audio_timestamp;
865
 
                }
866
 
 
867
 
                // update video clock for next frame
868
 
                boost::uint32_t frame_delay;
869
 
                if (!m_isFLV)
870
 
                {
871
 
                        frame_delay = static_cast<boost::uint32_t>((as_double(m_audio_stream->time_base) * packet->dts) * 1000.0);
872
 
                }
873
 
                else
874
 
                {
875
 
                        frame_delay = m_parser->audioFrameDelay();
876
 
                }
877
 
 
878
 
                m_last_audio_timestamp += frame_delay;
879
 
 
880
 
                if (m_isFLV) m_qaudio.push(raw);
881
 
                else m_unqueued_data = m_qaudio.push(raw) ? NULL : raw;
882
 
        }
883
 
        return true;
884
 
}
885
 
 
886
 
 
887
 
bool NetStreamFfmpeg::decodeVideo(AVPacket* packet)
888
 
{
889
 
        if (!m_VCodecCtx) return false;
890
 
 
891
 
        int got = 0;
892
 
        avcodec_decode_video(m_VCodecCtx, m_Frame, &got, packet->data, packet->size);
893
 
        if (got)
894
 
        {
895
 
                if (m_imageframe == NULL)
896
 
                {
897
 
                        if (m_videoFrameFormat == render::YUV)
898
 
                        {
899
 
                                m_imageframe = new image::yuv(m_VCodecCtx->width, m_VCodecCtx->height);
900
 
                        }
901
 
                        else if (m_videoFrameFormat == render::RGB)
902
 
                        {
903
 
                                m_imageframe = new image::rgb(m_VCodecCtx->width, m_VCodecCtx->height);
904
 
                        }
905
 
                }
906
 
 
907
 
                AVPicture rgbpicture;
908
 
 
909
 
                if (m_videoFrameFormat == render::NONE)
910
 
                {
911
 
                        // NullGui?
912
 
                        return false;
913
 
 
914
 
                }
915
 
                else if (m_videoFrameFormat == render::YUV && m_VCodecCtx->pix_fmt != PIX_FMT_YUV420P)
916
 
                {
917
 
                        assert( 0 );    // TODO
918
 
                        //img_convert((AVPicture*) pFrameYUV, PIX_FMT_YUV420P, (AVPicture*) pFrame, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
919
 
                        // Don't use depreceted img_convert, use sws_scale
920
 
 
921
 
                }
922
 
                else if (m_videoFrameFormat == render::RGB && m_VCodecCtx->pix_fmt != PIX_FMT_RGB24)
923
 
                {
924
 
                        rgbpicture = media::VideoDecoderFfmpeg::convertRGB24(m_VCodecCtx, *m_Frame);
925
 
                        if (!rgbpicture.data[0]) {
926
 
                                return false;
927
 
                        }
928
 
                }
929
 
 
930
 
                media::raw_mediadata_t* video = new media::raw_mediadata_t();
931
 
 
932
 
                if (m_videoFrameFormat == render::YUV)
933
 
                {
934
 
                        video->m_data = new boost::uint8_t[static_cast<image::yuv*>(m_imageframe)->size()];
935
 
                }
936
 
                else if (m_videoFrameFormat == render::RGB)
937
 
                {
938
 
                        image::rgb* tmp = static_cast<image::rgb*>(m_imageframe);
939
 
                        video->m_data = new boost::uint8_t[tmp->pitch() * tmp->height()];
940
 
                }
941
 
 
942
 
                video->m_ptr = video->m_data;
943
 
                video->m_stream_index = m_video_index;
944
 
                video->m_pts = 0;
945
 
 
946
 
                // set presentation timestamp
947
 
                if (packet->dts != static_cast<signed long>(AV_NOPTS_VALUE))
948
 
                {
949
 
                        if (!m_isFLV)   video->m_pts = static_cast<boost::uint32_t>((as_double(m_video_stream->time_base) * packet->dts) * 1000.0);
950
 
                        else video->m_pts = static_cast<boost::uint32_t>((as_double(m_VCodecCtx->time_base) * packet->dts) * 1000.0);
951
 
                }
952
 
 
953
 
                if (video->m_pts != 0)
954
 
                {       
955
 
                        // update video clock with pts, if present
956
 
                        m_last_video_timestamp = video->m_pts;
957
 
                }
958
 
                else
959
 
                {
960
 
                        video->m_pts = m_last_video_timestamp;
961
 
                }
962
 
 
963
 
                // update video clock for next frame
964
 
                boost::uint32_t frame_delay;
965
 
                if (!m_isFLV) frame_delay = static_cast<boost::uint32_t>(as_double(m_video_stream->codec->time_base) * 1000.0);
966
 
                else frame_delay = m_parser->videoFrameDelay();
967
 
 
968
 
                // for MPEG2, the frame can be repeated, so we update the clock accordingly
969
 
                frame_delay += static_cast<boost::uint32_t>(m_Frame->repeat_pict * (frame_delay * 0.5) * 1000.0);
970
 
 
971
 
                m_last_video_timestamp += frame_delay;
972
 
 
973
 
                if (m_videoFrameFormat == render::YUV)
974
 
                {
975
 
                        image::yuv* yuvframe = static_cast<image::yuv*>(m_imageframe);
976
 
                        int copied = 0;
977
 
                        boost::uint8_t* ptr = video->m_data;
978
 
                        for (int i = 0; i < 3 ; i++)
979
 
                        {
980
 
                                int shift = (i == 0 ? 0 : 1);
981
 
                                boost::uint8_t* yuv_factor = m_Frame->data[i];
982
 
                                int h = m_VCodecCtx->height >> shift;
983
 
                                int w = m_VCodecCtx->width >> shift;
984
 
                                for (int j = 0; j < h; j++)
985
 
                                {
986
 
                                        copied += w;
987
 
                                        assert(copied <= yuvframe->size());
988
 
                                        memcpy(ptr, yuv_factor, w);
989
 
                                        yuv_factor += m_Frame->linesize[i];
990
 
                                        ptr += w;
991
 
                                }
992
 
                        }
993
 
                        video->m_size = copied;
994
 
                }
995
 
                else if (m_videoFrameFormat == render::RGB)
996
 
                {
997
 
                        AVPicture* src;
998
 
                        if (m_VCodecCtx->pix_fmt != PIX_FMT_RGB24)
999
 
                        {
1000
 
                                src = &rgbpicture;
1001
 
                        } else
1002
 
                        {
1003
 
                                src = (AVPicture*) m_Frame;
1004
 
                        }
1005
 
                
1006
 
                        boost::uint8_t* srcptr = src->data[0];            
1007
 
                        boost::uint8_t* srcend = srcptr + rgbpicture.linesize[0] * m_VCodecCtx->height;
1008
 
                        boost::uint8_t* dstptr = video->m_data;
1009
 
                        unsigned int srcwidth = m_VCodecCtx->width * 3;
1010
 
 
1011
 
                        video->m_size = 0;
1012
 
 
1013
 
                        while (srcptr < srcend) {
1014
 
                                memcpy(dstptr, srcptr, srcwidth);
1015
 
                                srcptr += src->linesize[0];
1016
 
                                dstptr += srcwidth;
1017
 
                                video->m_size += srcwidth;
1018
 
                        }
1019
 
                        
1020
 
                        if (m_VCodecCtx->pix_fmt != PIX_FMT_RGB24) {
1021
 
                                delete [] rgbpicture.data[0];
1022
 
                        }
1023
 
 
1024
 
                }
1025
 
 
1026
 
                if (m_isFLV) m_qvideo.push(video);
1027
 
                else m_unqueued_data = m_qvideo.push(video) ? NULL : video;
1028
 
 
1029
 
                return true;
1030
 
        }
1031
 
 
1032
 
        return false;
1033
 
}
1034
 
 
1035
 
bool NetStreamFfmpeg::decodeMediaFrame()
1036
 
{
1037
 
 
1038
 
        if (m_unqueued_data)
1039
 
        {
1040
 
                if (m_unqueued_data->m_stream_index == m_audio_index)
1041
 
                {
1042
 
                        media::sound_handler* s = get_sound_handler();
1043
 
                        if (s)
1044
 
                        {
1045
 
                                m_unqueued_data = m_qaudio.push(m_unqueued_data) ? NULL : m_unqueued_data;
1046
 
                        }
1047
 
                }
1048
 
                else if (m_unqueued_data->m_stream_index == m_video_index)
1049
 
                {
1050
 
                        m_unqueued_data = m_qvideo.push(m_unqueued_data) ? NULL : m_unqueued_data;
1051
 
                }
1052
 
                else
1053
 
                {
1054
 
                        log_error(_("read_frame: not audio & video stream"));
1055
 
                }
1056
 
                return true;
1057
 
        }
1058
 
 
1059
 
        AVPacket packet;
1060
 
        
1061
 
        int rc = av_read_frame(m_FormatCtx, &packet);
1062
 
 
1063
 
        if (rc >= 0)
1064
 
        {
1065
 
                if (packet.stream_index == m_audio_index && get_sound_handler())
1066
 
                {
1067
 
                        if (!decodeAudio(&packet)) 
1068
 
                        {
1069
 
                                log_error(_("Problems decoding audio frame"));
1070
 
                                return false;
1071
 
                        }
1072
 
                }
1073
 
                else
1074
 
                if (packet.stream_index == m_video_index)
1075
 
                {
1076
 
                        if (!decodeVideo(&packet)) 
1077
 
                        {
1078
 
                                log_error(_("Problems decoding video frame"));
1079
 
                                return false;
1080
 
                        }
1081
 
                }
1082
 
                av_free_packet(&packet);
1083
 
        }
1084
 
        else
1085
 
        {
1086
 
                log_error(_("Problems decoding frame"));
1087
 
                return false;
1088
 
        }
1089
 
 
1090
 
        return true;
1091
 
}
1092
 
 
1093
 
void
1094
 
NetStreamFfmpeg::seek(boost::uint32_t pos)
1095
 
{
1096
 
        long newpos = 0;
1097
 
        double timebase = 0;
1098
 
 
1099
 
        // Seek to new position
1100
 
        if (m_isFLV)
1101
 
        {
1102
 
                if (m_parser.get())
1103
 
                {
1104
 
                        newpos = m_parser->seek(pos);
1105
 
                }
1106
 
                else
1107
 
                {
1108
 
                        newpos = 0;
1109
 
                }
1110
 
        }
1111
 
        else if (m_FormatCtx)
1112
 
        {
1113
 
 
1114
 
                AVStream* videostream = m_FormatCtx->streams[m_video_index];
1115
 
                timebase = static_cast<double>(videostream->time_base.num / videostream->time_base.den);
1116
 
                newpos = static_cast<long>(pos / timebase);
1117
 
                
1118
 
                if (av_seek_frame(m_FormatCtx, m_video_index, newpos, 0) < 0)
1119
 
                {
1120
 
                        log_error(_("%s: seeking failed"), __FUNCTION__);
1121
 
                        return;
1122
 
                }
1123
 
        }
1124
 
        else
1125
 
        {
1126
 
                // TODO: should we log_debug ??
1127
 
                return;
1128
 
        }
1129
 
 
1130
 
        // This is kindof hackish and ugly :-(
1131
 
        if (newpos == 0)
1132
 
        {
1133
 
                m_last_video_timestamp = 0;
1134
 
                m_last_audio_timestamp = 0;
1135
 
                m_current_timestamp = 0;
1136
 
 
1137
 
                m_start_clock = tu_timer::get_ticks();
1138
 
 
1139
 
        }
1140
 
        else if (m_isFLV)
1141
 
        {
1142
 
 
1143
 
                if (m_VCodecCtx) m_start_clock += m_last_video_timestamp - newpos;
1144
 
                else m_start_clock += m_last_audio_timestamp - newpos;
1145
 
 
1146
 
                if (m_ACodecCtx) m_last_audio_timestamp = newpos;
1147
 
                if (m_VCodecCtx) m_last_video_timestamp = newpos;
1148
 
                m_current_timestamp = newpos;
1149
 
        }
1150
 
        else
1151
 
        {
1152
 
                AVPacket Packet;
1153
 
                av_init_packet(&Packet);
1154
 
                double newtime = 0;
1155
 
                while (newtime == 0)
1156
 
                {
1157
 
                        if (av_read_frame(m_FormatCtx, &Packet) < 0) 
1158
 
                        {
1159
 
                                av_seek_frame(m_FormatCtx, -1, 0, AVSEEK_FLAG_BACKWARD);
1160
 
                                av_free_packet( &Packet );
1161
 
                                return;
1162
 
                        }
1163
 
 
1164
 
                        newtime = timebase * (double)m_FormatCtx->streams[m_video_index]->cur_dts;
1165
 
                }
1166
 
 
1167
 
                av_free_packet( &Packet );
1168
 
 
1169
 
                av_seek_frame(m_FormatCtx, m_video_index, newpos, 0);
1170
 
                boost::uint32_t newtime_ms = static_cast<boost::int32_t>(newtime / 1000.0);
1171
 
                m_start_clock += m_last_audio_timestamp - newtime_ms;
1172
 
 
1173
 
                m_last_audio_timestamp = newtime_ms;
1174
 
                m_last_video_timestamp = newtime_ms;
1175
 
                m_current_timestamp = newtime_ms;
1176
 
        }
1177
 
        
1178
 
        // Flush the queues
1179
 
        while ( m_qvideo.size() > 0 ) 
1180
 
        {
1181
 
                delete m_qvideo.front();
1182
 
                m_qvideo.pop();
1183
 
        }
1184
 
        while ( m_qaudio.size() > 0 ) 
1185
 
        {
1186
 
                delete m_qaudio.front();
1187
 
                m_qaudio.pop();
1188
 
        }
1189
 
 
1190
 
}
1191
 
 
1192
 
void
1193
 
NetStreamFfmpeg::refreshVideoFrame()
1194
 
{
1195
 
        // If we're paused or not running, there is no need to do this
1196
 
        if (!m_go || m_pause) return;
1197
 
 
1198
 
        // Loop until a good frame is found
1199
 
        while(1)
1200
 
        {
1201
 
                // Get video frame from queue, will have the lowest timestamp
1202
 
                // will return NULL if empty(). See multithread_queue::front
1203
 
                media::raw_mediadata_t* video = m_qvideo.front();
1204
 
 
1205
 
                // If the queue is empty we have nothing to do
1206
 
                if (!video)
1207
 
                {
1208
 
                        return;
1209
 
                }
1210
 
 
1211
 
                // Caclulate the current time
1212
 
                boost::uint32_t current_clock;
1213
 
                if (m_ACodecCtx && get_sound_handler())
1214
 
                {
1215
 
                        current_clock = m_current_timestamp;
1216
 
                }
1217
 
                else
1218
 
                {
1219
 
                        current_clock = tu_timer::get_ticks() - m_start_clock;
1220
 
                        m_current_timestamp = current_clock;
1221
 
                }
1222
 
 
1223
 
                boost::uint32_t video_clock = video->m_pts;
1224
 
 
1225
 
                // If the timestamp on the videoframe is smaller than the
1226
 
                // current time, we put it in the output image.
1227
 
                if (current_clock >= video_clock)
1228
 
                {
1229
 
                        boost::mutex::scoped_lock lock(image_mutex);
1230
 
                        if (m_videoFrameFormat == render::YUV)
1231
 
                        {
1232
 
                                // XXX m_imageframe might be a byte aligned buffer, while video is not!
1233
 
                                static_cast<image::yuv*>(m_imageframe)->update(video->m_data);
1234
 
                        }
1235
 
                        else if (m_videoFrameFormat == render::RGB)
1236
 
                        {
1237
 
 
1238
 
                                image::rgb* imgframe = static_cast<image::rgb*>(m_imageframe);
1239
 
                                rgbcopy(imgframe, video, m_VCodecCtx->width * 3);
1240
 
                        }
1241
 
 
1242
 
                        // Delete the frame from the queue
1243
 
                        m_qvideo.pop();
1244
 
                        delete video;
1245
 
 
1246
 
                        // A frame is ready for pickup
1247
 
                        m_newFrameReady = true;
1248
 
 
1249
 
                }
1250
 
                else
1251
 
                {
1252
 
                        // The timestamp on the first frame in the queue is greater
1253
 
                        // than the current time, so no need to do anything.
1254
 
                        return;
1255
 
                }
1256
 
 
1257
 
        }
1258
 
}
1259
 
 
1260
 
 
1261
 
void
1262
 
NetStreamFfmpeg::advance()
1263
 
{
1264
 
 
1265
 
        // Make sure al decoding has stopped
1266
 
        // This can happen in 2 cases: 
1267
 
        // 1) When playback has just started and we've been waiting for the buffer 
1268
 
        //    to be filled (buffersize set by setBufferTime() and default is 100
1269
 
        //    miliseconds).
1270
 
        // 2) The buffer has be "starved" (not being filled as quickly as needed),
1271
 
        //    and we then wait until the buffer contains some data (1 sec) again.
1272
 
        if (m_go && m_pause && m_start_onbuffer && m_parser.get() && m_parser->isTimeLoaded(m_current_timestamp+m_bufferTime))
1273
 
        {
1274
 
#ifdef GNASH_DEBUG_STATUS
1275
 
                log_debug("(advance): setting buffer full");
1276
 
#endif
1277
 
                setStatus(bufferFull);
1278
 
                unpausePlayback();
1279
 
                m_start_onbuffer = false;
1280
 
        }
1281
 
 
1282
 
        //log_debug("(advance): processing status notification, refreshing video frame");
1283
 
 
1284
 
        // Check if there are any new status messages, and if we should
1285
 
        // pass them to a event handler
1286
 
        processStatusNotifications();
1287
 
 
1288
 
        // Find video frame with the most suited timestamp in the video queue,
1289
 
        // and put it in the output image frame.
1290
 
        refreshVideoFrame();
1291
 
}
1292
 
 
1293
 
boost::int32_t
1294
 
NetStreamFfmpeg::time()
1295
 
{
1296
 
 
1297
 
        if (m_FormatCtx && m_FormatCtx->nb_streams > 0)
1298
 
        {
1299
 
                double time = (double)m_FormatCtx->streams[0]->time_base.num / (double)m_FormatCtx->streams[0]->time_base.den * (double)m_FormatCtx->streams[0]->cur_dts;
1300
 
                return static_cast<boost::int32_t>(time);
1301
 
        }
1302
 
        else if
1303
 
        (m_isFLV)
1304
 
        {
1305
 
                return m_current_timestamp;
1306
 
        }
1307
 
        else
1308
 
        {
1309
 
                return 0;
1310
 
        }
1311
 
}
1312
 
 
1313
 
void NetStreamFfmpeg::pausePlayback()
1314
 
{
1315
 
        //GNASH_REPORT_FUNCTION
1316
 
 
1317
 
        if (m_pause) return;
1318
 
 
1319
 
        m_pause = true;
1320
 
 
1321
 
        // Save the current time so we later can tell how long the pause lasted
1322
 
        m_time_of_pause = tu_timer::get_ticks();
1323
 
}
1324
 
 
1325
 
void NetStreamFfmpeg::unpausePlayback()
1326
 
{
1327
 
        if (!m_pause) // already not paused
1328
 
        {
1329
 
                return;
1330
 
        }
1331
 
 
1332
 
        m_pause = false;        
1333
 
 
1334
 
        if (m_current_timestamp == 0)
1335
 
        {
1336
 
                m_start_clock = tu_timer::get_ticks();
1337
 
        }
1338
 
        else
1339
 
        {
1340
 
                // Add the paused time to the start time so that the playhead doesn't
1341
 
                // noticed that we have been paused
1342
 
                m_start_clock += tu_timer::get_ticks() - m_time_of_pause;
1343
 
        }
1344
 
 
1345
 
        // Re-connect to the soundhandler.
1346
 
        // It was disconnected to avoid to keep playing sound while paused
1347
 
        media::sound_handler* s = get_sound_handler();
1348
 
        if ( s )     s->attach_aux_streamer(audio_streamer, (void*) this);
1349
 
}
1350
 
 
1351
 
 
1352
 
long
1353
 
NetStreamFfmpeg::bytesLoaded ()
1354
 
{
1355
 
        long ret_val = 0;
1356
 
 
1357
 
        if ( _netCon ) 
1358
 
        {
1359
 
                ret_val = _netCon->getBytesLoaded();
1360
 
        }
1361
 
 
1362
 
        return ret_val;
1363
 
}
1364
 
 
1365
 
 
1366
 
long
1367
 
NetStreamFfmpeg::bytesTotal ()
1368
 
{
1369
 
        long ret_val = 0;
1370
 
 
1371
 
        if ( _netCon ) 
1372
 
        {
1373
 
                ret_val = _netCon->getBytesTotal();
1374
 
        }
1375
 
 
1376
 
        return ret_val;
1377
 
}
1378
 
 
1379
 
 
1380
 
} // gnash namespcae
1381
 
 
1382
 
#endif // USE_FFMPEG
1383