1
// NetStreamFfmpeg.cpp: Network streaming for FFMPEG video library, for Gnash.
3
// Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
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.
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
/* $Id: NetStreamFfmpeg.cpp,v 1.105.2.2 2008/02/27 20:55:02 bjacques Exp $ */
23
#include "gnashconfig.h"
28
#include "NetStreamFfmpeg.h"
31
#include "NetStream.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 ?
38
#include <boost/scoped_array.hpp>
41
#if defined(_WIN32) || defined(WIN32)
42
# include <windows.h> // for sleep()
43
# define usleep(x) Sleep(x/1000)
45
# include "unistd.h" // for usleep()
48
/// Define this to add debugging prints for locking
49
//#define GNASH_DEBUG_THREADS
51
// Define the following macro to have status notification handling debugged
52
//#define GNASH_DEBUG_STATUS
54
// Used to free data in the AVPackets we create our self
55
static void avpacket_destruct(AVPacket* av)
64
NetStreamFfmpeg::NetStreamFfmpeg():
75
m_last_video_timestamp(0),
76
m_last_audio_timestamp(0),
77
m_current_timestamp(0),
78
m_unqueued_data(NULL),
82
ByteIOCxt.buffer = NULL;
85
NetStreamFfmpeg::~NetStreamFfmpeg()
91
void NetStreamFfmpeg::pause( PauseMode mode )
104
case pauseModeUnPause:
111
if ( !m_pause && !m_go ) {
112
setStatus( playStart );
115
_decodeThread = new boost::thread( boost::bind(NetStreamFfmpeg::av_streamer, this) );
119
void NetStreamFfmpeg::close()
124
// request decoder thread termination
127
// wait till thread is complete before main continues
128
_decodeThread->join();
130
delete _decodeThread;
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();
139
s->detach_aux_streamer(this);
142
if (m_Frame) av_free(m_Frame);
146
avcodec_close( m_VCodecCtx );
151
avcodec_close( m_ACodecCtx );
157
m_FormatCtx->iformat->flags = AVFMT_NOFILE;
158
av_close_input_file(m_FormatCtx);
164
delete m_unqueued_data;
165
m_unqueued_data = NULL;
167
while (m_qvideo.size() > 0)
169
delete m_qvideo.front();
173
while (m_qaudio.size() > 0)
175
delete m_qaudio.front();
179
delete [] ByteIOCxt.buffer;
183
// ffmpeg callback function
185
NetStreamFfmpeg::readPacket(void* opaque, boost::uint8_t* buf, int buf_size)
188
NetStreamFfmpeg* ns = static_cast<NetStreamFfmpeg*>(opaque);
189
boost::intrusive_ptr<NetConnection> nc = ns->_netCon;
191
size_t ret = nc->read(static_cast<void*>(buf), buf_size);
197
// ffmpeg callback function
199
NetStreamFfmpeg::seekMedia(void *opaque, offset_t offset, int whence)
202
NetStreamFfmpeg* ns = static_cast<NetStreamFfmpeg*>(opaque);
203
boost::intrusive_ptr<NetConnection> nc = ns->_netCon;
206
// Offset is absolute new position in the file
207
if (whence == SEEK_SET)
210
ns->inputPos = offset;
212
// New position is offset + old position
214
else if (whence == SEEK_CUR)
216
nc->seek(ns->inputPos + offset);
217
ns->inputPos = ns->inputPos + offset;
219
// New position is offset + end of file
221
else if (whence == SEEK_END)
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...
226
ns->inputPos = 50000;
234
NetStreamFfmpeg::play(const std::string& c_url)
237
// Is it already playing ?
240
unpausePlayback(); // will check for m_pause itself..
244
// Does it have an associated NetConnection ?
247
IF_VERBOSE_ASCODING_ERRORS(
248
log_aserror(_("No NetConnection associated with this NetStream, won't play"));
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)
263
// This starts the decoding thread
264
_decodeThread = new boost::thread(boost::bind(NetStreamFfmpeg::av_streamer, this));
269
/// Finds a decoder, allocates a context and initializes it.
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)
278
AVCodec* codec = avcodec_find_decoder(codec_id);
281
log_error(_("libavcodec couldn't find decoder"));
285
AVCodecContext * context = avcodec_alloc_context();
288
log_error(_("libavcodec couldn't allocate context"));
292
int rv = avcodec_open(context, codec);
295
avcodec_close(context);
296
log_error(_("libavcodec failed to initialize codec"));
303
/// Gets video info from the parser and initializes the codec.
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)
311
// Get video info from the parser
312
std::auto_ptr<FLVVideoInfo> videoInfo( parser->getVideoInfo() );
313
if (!videoInfo.get())
318
enum CodecID codec_id;
320
// Find the decoder and init the parser
321
switch(videoInfo->codec)
323
case media::VIDEO_CODEC_H263:
324
codec_id = CODEC_ID_FLV1;
327
case media::VIDEO_CODEC_VP6:
328
codec_id = CODEC_ID_VP6F;
331
case media::VIDEO_CODEC_SCREENVIDEO:
332
codec_id = CODEC_ID_FLASHSV;
335
log_error(_("Unsupported video codec %d"), (int) videoInfo->codec);
339
return initContext(codec_id);
343
/// Like initFlvVideo, but for audio.
344
static AVCodecContext*
345
initFlvAudio(FLVParser* parser)
347
// Get audio info from the parser
348
std::auto_ptr<FLVAudioInfo> audioInfo( parser->getAudioInfo() );
349
if (!audioInfo.get())
354
enum CodecID codec_id;
356
switch(audioInfo->codec)
358
case media::AUDIO_CODEC_RAW:
359
codec_id = CODEC_ID_PCM_U16LE;
361
case media::AUDIO_CODEC_ADPCM:
362
codec_id = CODEC_ID_ADPCM_SWF;
364
case media::AUDIO_CODEC_MP3:
365
codec_id = CODEC_ID_MP3;
368
log_error(_("Unsupported audio codec %d"), (int)audioInfo->codec);
372
return initContext(codec_id);
376
/// Probe the stream and try to figure out what the format is.
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)
384
boost::scoped_array<boost::uint8_t> buffer(new boost::uint8_t[2048]);
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;
392
if (ns->readPacket(ns, probe_data.buf, probe_data.buf_size) < 1)
394
log_error(_("Gnash could not read from movie url"));
398
return av_probe_input_format(&probe_data, 1);
402
NetStreamFfmpeg::startPlayback()
405
boost::intrusive_ptr<NetConnection> nc = _netCon;
408
// Pass stuff from/to the NetConnection object.
409
if ( !nc->openConnection(url) )
411
log_error(_("Gnash could not open movie: %s"), url.c_str());
412
setStatus(streamNotFound);
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)
423
setStatus(streamNotFound);
428
if (std::string(head) == "FLV")
433
m_parser = nc->getConnectedParser();
434
if (! m_parser.get() )
436
setStatus(streamNotFound);
437
log_error(_("Gnash could not open FLV movie: %s"), url.c_str());
442
// Init the avdecoder-decoder
444
avcodec_register_all();
446
m_VCodecCtx = initFlvVideo(m_parser.get());
449
log_error(_("Failed to initialize FLV video codec"));
453
m_ACodecCtx = initFlvAudio(m_parser.get());
456
log_error(_("Failed to initialize FLV audio codec"));
460
// We just define the indexes here, they're not really used when
461
// the file format is FLV
465
m_start_onbuffer = true;
467
// Allocate a frame to store the decoded frame in
468
m_Frame = avcodec_alloc_frame();
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?
478
AVInputFormat* inputFmt = probeStream(this);
481
log_error(_("Couldn't determine stream input format from URL %s"), url.c_str());
485
// After the format probe, reset to the beginning of the file.
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;
493
m_FormatCtx = av_alloc_format_context();
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)
498
log_error(_("Couldn't open file '%s' for decoding"), url.c_str());
499
setStatus(streamNotFound);
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);
508
log_error(_("Couldn't find stream information from '%s', error code: %d"), url.c_str(), ret);
512
// m_FormatCtx->pb.eof_reached = 0;
513
// av_read_play(m_FormatCtx);
515
// Find the first video & audio stream
518
//assert(m_FormatCtx->nb_streams >= 0); useless assert.
519
for (unsigned int i = 0; i < (unsigned)m_FormatCtx->nb_streams; i++)
521
AVCodecContext* enc = m_FormatCtx->streams[i]->codec;
523
switch (enc->codec_type)
525
case CODEC_TYPE_AUDIO:
526
if (m_audio_index < 0)
529
m_audio_stream = m_FormatCtx->streams[i];
533
case CODEC_TYPE_VIDEO:
534
if (m_video_index < 0)
537
m_video_stream = m_FormatCtx->streams[i];
545
if (m_video_index < 0)
547
log_error(_("Didn't find a video stream from '%s'"), url.c_str());
551
// Get a pointer to the codec context for the video stream
552
m_VCodecCtx = m_FormatCtx->streams[m_video_index]->codec;
554
// Find the decoder for the video stream
555
AVCodec* pCodec = avcodec_find_decoder(m_VCodecCtx->codec_id);
559
log_error(_("Video decoder %d not found"),
560
m_VCodecCtx->codec_id);
565
if (avcodec_open(m_VCodecCtx, pCodec) < 0)
567
log_error(_("Could not open codec %d"),
568
m_VCodecCtx->codec_id);
571
// Allocate a frame to store the decoded frame in
572
m_Frame = avcodec_alloc_frame();
574
// Determine required buffer size and allocate buffer
575
if (m_videoFrameFormat == render::YUV)
577
m_imageframe = new image::yuv(m_VCodecCtx->width, m_VCodecCtx->height);
579
else if (m_videoFrameFormat == render::RGB)
581
m_imageframe = new image::rgb(m_VCodecCtx->width, m_VCodecCtx->height);
584
media::sound_handler* s = get_sound_handler();
585
if (m_audio_index >= 0 && s != NULL)
587
// Get a pointer to the audio codec context for the video stream
588
m_ACodecCtx = m_FormatCtx->streams[m_audio_index]->codec;
590
// Find the decoder for the audio stream
591
AVCodec* pACodec = avcodec_find_decoder(m_ACodecCtx->codec_id);
594
log_error(_("No available audio decoder %d to process MPEG file: '%s'"),
595
m_ACodecCtx->codec_id, url.c_str());
600
if (avcodec_open(m_ACodecCtx, pACodec) < 0)
602
log_error(_("Could not open audio codec %d for %s"),
603
m_ACodecCtx->codec_id, url.c_str());
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.
621
rgbcopy(image::rgb* dst, media::raw_mediadata_t* src, int width)
623
assert( src->m_size <= static_cast<boost::uint32_t>(dst->width() * dst->height() * 3) );
625
boost::uint8_t* dstptr = dst->data();
627
boost::uint8_t* srcptr = src->m_data;
628
boost::uint8_t* srcend = src->m_data + src->m_size;
630
while (srcptr < srcend) {
631
memcpy(dstptr, srcptr, width);
632
dstptr += dst->pitch();
638
void NetStreamFfmpeg::av_streamer(NetStreamFfmpeg* ns)
640
//GNASH_REPORT_FUNCTION;
642
// This should only happen if close() is called before this thread is ready
645
log_debug("av_streamer: !ns->m_go, returning");
649
if (!ns->m_ACodecCtx && !ns->m_VCodecCtx && !ns->m_FormatCtx)
651
if (!ns->startPlayback())
653
log_debug("av_streamer: !ns->startPlayback, returning");
659
// We need to restart the audio
660
media::sound_handler* s = get_sound_handler();
663
s->attach_aux_streamer(audio_streamer, ns);
667
ns->setStatus(playStart);
669
ns->m_last_video_timestamp = 0;
670
ns->m_last_audio_timestamp = 0;
671
ns->m_current_timestamp = 0;
673
ns->m_start_clock = tu_timer::get_ticks();
675
ns->m_unqueued_data = NULL;
677
// Loop while we're playing
680
#ifdef GNASH_DEBUG_THREADS
681
log_debug("Decoding iteration. bufferTime=%lu, bufferLen=%lu", ns->bufferTime(), ns->bufferLength());
686
// If queues are full then don't bother filling it
687
if ( ns->m_qvideo.size() < 20 || ns->m_qaudio.size() < 20 )
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)
693
// TODO: do we really want to break here !?
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)
710
usleep(1); // task switch, to avoid 100% CPU
714
#ifdef GNASH_DEBUG_THREADS
715
log_debug("Out of decoding loop");
719
#ifdef GNASH_DEBUG_STATUS
720
log_debug("Setting playStop status");
722
ns->setStatus(playStop);
725
// audio callback is running in sound handler thread
726
bool NetStreamFfmpeg::audio_streamer(void *owner, boost::uint8_t *stream, int len)
728
//GNASH_REPORT_FUNCTION;
730
NetStreamFfmpeg* ns = static_cast<NetStreamFfmpeg*>(owner);
732
if (!ns->m_go || ns->m_pause)
737
while (len > 0 && ns->m_qaudio.size() > 0)
739
media::raw_mediadata_t* samples = ns->m_qaudio.front();
741
int n = imin(samples->m_size, len);
742
memcpy(stream, samples->m_ptr, n);
745
samples->m_size -= n;
748
ns->m_current_timestamp = samples->m_pts;
750
if (samples->m_size == 0)
760
bool NetStreamFfmpeg::decodeFLVFrame()
762
FLVFrame* frame = NULL;
763
if ( m_qvideo.size() < m_qaudio.size() )
765
frame = m_parser->nextVideoFrame();
767
frame = m_parser->nextAudioFrame();
772
if (_netCon->loadCompleted())
774
#ifdef GNASH_DEBUG_THREADS
775
log_debug("decodeFLVFrame: load completed, stopping");
783
setStatus(bufferEmpty);
784
m_start_onbuffer = true;
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);
799
packet.stream_index = 0;
800
return decodeVideo(&packet);
804
packet.stream_index = 1;
805
return decodeAudio(&packet);
811
bool NetStreamFfmpeg::decodeAudio( AVPacket* packet )
813
if (!m_ACodecCtx) return false;
816
unsigned int bufsize = (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2;
818
boost::uint8_t* ptr = new boost::uint8_t[bufsize];
820
frame_size = bufsize;
821
if (avcodec_decode_audio2(m_ACodecCtx, (boost::int16_t*) ptr, &frame_size, packet->data, packet->size) >= 0)
823
if (avcodec_decode_audio(m_ACodecCtx, (boost::int16_t*) ptr, &frame_size, packet->data, packet->size) >= 0)
827
bool stereo = m_ACodecCtx->channels > 1 ? true : false;
828
int samples = stereo ? frame_size >> 2 : frame_size >> 1;
830
if (_resampler.init(m_ACodecCtx))
832
// Resampling is needed.
834
boost::uint8_t* output = new boost::uint8_t[bufsize];
836
samples = _resampler.resample(reinterpret_cast<boost::int16_t*>(ptr),
837
reinterpret_cast<boost::int16_t*>(output),
840
ptr = reinterpret_cast<boost::uint8_t*>(output);
843
media::raw_mediadata_t* raw = new media::raw_mediadata_t();
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;
850
// set presentation timestamp
851
if (packet->dts != static_cast<signed long>(AV_NOPTS_VALUE))
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);
859
// update audio clock with pts, if present
860
m_last_audio_timestamp = raw->m_pts;
864
raw->m_pts = m_last_audio_timestamp;
867
// update video clock for next frame
868
boost::uint32_t frame_delay;
871
frame_delay = static_cast<boost::uint32_t>((as_double(m_audio_stream->time_base) * packet->dts) * 1000.0);
875
frame_delay = m_parser->audioFrameDelay();
878
m_last_audio_timestamp += frame_delay;
880
if (m_isFLV) m_qaudio.push(raw);
881
else m_unqueued_data = m_qaudio.push(raw) ? NULL : raw;
887
bool NetStreamFfmpeg::decodeVideo(AVPacket* packet)
889
if (!m_VCodecCtx) return false;
892
avcodec_decode_video(m_VCodecCtx, m_Frame, &got, packet->data, packet->size);
895
if (m_imageframe == NULL)
897
if (m_videoFrameFormat == render::YUV)
899
m_imageframe = new image::yuv(m_VCodecCtx->width, m_VCodecCtx->height);
901
else if (m_videoFrameFormat == render::RGB)
903
m_imageframe = new image::rgb(m_VCodecCtx->width, m_VCodecCtx->height);
907
AVPicture rgbpicture;
909
if (m_videoFrameFormat == render::NONE)
915
else if (m_videoFrameFormat == render::YUV && m_VCodecCtx->pix_fmt != PIX_FMT_YUV420P)
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
922
else if (m_videoFrameFormat == render::RGB && m_VCodecCtx->pix_fmt != PIX_FMT_RGB24)
924
rgbpicture = media::VideoDecoderFfmpeg::convertRGB24(m_VCodecCtx, *m_Frame);
925
if (!rgbpicture.data[0]) {
930
media::raw_mediadata_t* video = new media::raw_mediadata_t();
932
if (m_videoFrameFormat == render::YUV)
934
video->m_data = new boost::uint8_t[static_cast<image::yuv*>(m_imageframe)->size()];
936
else if (m_videoFrameFormat == render::RGB)
938
image::rgb* tmp = static_cast<image::rgb*>(m_imageframe);
939
video->m_data = new boost::uint8_t[tmp->pitch() * tmp->height()];
942
video->m_ptr = video->m_data;
943
video->m_stream_index = m_video_index;
946
// set presentation timestamp
947
if (packet->dts != static_cast<signed long>(AV_NOPTS_VALUE))
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);
953
if (video->m_pts != 0)
955
// update video clock with pts, if present
956
m_last_video_timestamp = video->m_pts;
960
video->m_pts = m_last_video_timestamp;
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();
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);
971
m_last_video_timestamp += frame_delay;
973
if (m_videoFrameFormat == render::YUV)
975
image::yuv* yuvframe = static_cast<image::yuv*>(m_imageframe);
977
boost::uint8_t* ptr = video->m_data;
978
for (int i = 0; i < 3 ; i++)
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++)
987
assert(copied <= yuvframe->size());
988
memcpy(ptr, yuv_factor, w);
989
yuv_factor += m_Frame->linesize[i];
993
video->m_size = copied;
995
else if (m_videoFrameFormat == render::RGB)
998
if (m_VCodecCtx->pix_fmt != PIX_FMT_RGB24)
1003
src = (AVPicture*) m_Frame;
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;
1013
while (srcptr < srcend) {
1014
memcpy(dstptr, srcptr, srcwidth);
1015
srcptr += src->linesize[0];
1017
video->m_size += srcwidth;
1020
if (m_VCodecCtx->pix_fmt != PIX_FMT_RGB24) {
1021
delete [] rgbpicture.data[0];
1026
if (m_isFLV) m_qvideo.push(video);
1027
else m_unqueued_data = m_qvideo.push(video) ? NULL : video;
1035
bool NetStreamFfmpeg::decodeMediaFrame()
1038
if (m_unqueued_data)
1040
if (m_unqueued_data->m_stream_index == m_audio_index)
1042
media::sound_handler* s = get_sound_handler();
1045
m_unqueued_data = m_qaudio.push(m_unqueued_data) ? NULL : m_unqueued_data;
1048
else if (m_unqueued_data->m_stream_index == m_video_index)
1050
m_unqueued_data = m_qvideo.push(m_unqueued_data) ? NULL : m_unqueued_data;
1054
log_error(_("read_frame: not audio & video stream"));
1061
int rc = av_read_frame(m_FormatCtx, &packet);
1065
if (packet.stream_index == m_audio_index && get_sound_handler())
1067
if (!decodeAudio(&packet))
1069
log_error(_("Problems decoding audio frame"));
1074
if (packet.stream_index == m_video_index)
1076
if (!decodeVideo(&packet))
1078
log_error(_("Problems decoding video frame"));
1082
av_free_packet(&packet);
1086
log_error(_("Problems decoding frame"));
1094
NetStreamFfmpeg::seek(boost::uint32_t pos)
1097
double timebase = 0;
1099
// Seek to new position
1104
newpos = m_parser->seek(pos);
1111
else if (m_FormatCtx)
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);
1118
if (av_seek_frame(m_FormatCtx, m_video_index, newpos, 0) < 0)
1120
log_error(_("%s: seeking failed"), __FUNCTION__);
1126
// TODO: should we log_debug ??
1130
// This is kindof hackish and ugly :-(
1133
m_last_video_timestamp = 0;
1134
m_last_audio_timestamp = 0;
1135
m_current_timestamp = 0;
1137
m_start_clock = tu_timer::get_ticks();
1143
if (m_VCodecCtx) m_start_clock += m_last_video_timestamp - newpos;
1144
else m_start_clock += m_last_audio_timestamp - newpos;
1146
if (m_ACodecCtx) m_last_audio_timestamp = newpos;
1147
if (m_VCodecCtx) m_last_video_timestamp = newpos;
1148
m_current_timestamp = newpos;
1153
av_init_packet(&Packet);
1155
while (newtime == 0)
1157
if (av_read_frame(m_FormatCtx, &Packet) < 0)
1159
av_seek_frame(m_FormatCtx, -1, 0, AVSEEK_FLAG_BACKWARD);
1160
av_free_packet( &Packet );
1164
newtime = timebase * (double)m_FormatCtx->streams[m_video_index]->cur_dts;
1167
av_free_packet( &Packet );
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;
1173
m_last_audio_timestamp = newtime_ms;
1174
m_last_video_timestamp = newtime_ms;
1175
m_current_timestamp = newtime_ms;
1179
while ( m_qvideo.size() > 0 )
1181
delete m_qvideo.front();
1184
while ( m_qaudio.size() > 0 )
1186
delete m_qaudio.front();
1193
NetStreamFfmpeg::refreshVideoFrame()
1195
// If we're paused or not running, there is no need to do this
1196
if (!m_go || m_pause) return;
1198
// Loop until a good frame is found
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();
1205
// If the queue is empty we have nothing to do
1211
// Caclulate the current time
1212
boost::uint32_t current_clock;
1213
if (m_ACodecCtx && get_sound_handler())
1215
current_clock = m_current_timestamp;
1219
current_clock = tu_timer::get_ticks() - m_start_clock;
1220
m_current_timestamp = current_clock;
1223
boost::uint32_t video_clock = video->m_pts;
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)
1229
boost::mutex::scoped_lock lock(image_mutex);
1230
if (m_videoFrameFormat == render::YUV)
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);
1235
else if (m_videoFrameFormat == render::RGB)
1238
image::rgb* imgframe = static_cast<image::rgb*>(m_imageframe);
1239
rgbcopy(imgframe, video, m_VCodecCtx->width * 3);
1242
// Delete the frame from the queue
1246
// A frame is ready for pickup
1247
m_newFrameReady = true;
1252
// The timestamp on the first frame in the queue is greater
1253
// than the current time, so no need to do anything.
1262
NetStreamFfmpeg::advance()
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
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))
1274
#ifdef GNASH_DEBUG_STATUS
1275
log_debug("(advance): setting buffer full");
1277
setStatus(bufferFull);
1279
m_start_onbuffer = false;
1282
//log_debug("(advance): processing status notification, refreshing video frame");
1284
// Check if there are any new status messages, and if we should
1285
// pass them to a event handler
1286
processStatusNotifications();
1288
// Find video frame with the most suited timestamp in the video queue,
1289
// and put it in the output image frame.
1290
refreshVideoFrame();
1294
NetStreamFfmpeg::time()
1297
if (m_FormatCtx && m_FormatCtx->nb_streams > 0)
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);
1305
return m_current_timestamp;
1313
void NetStreamFfmpeg::pausePlayback()
1315
//GNASH_REPORT_FUNCTION
1317
if (m_pause) return;
1321
// Save the current time so we later can tell how long the pause lasted
1322
m_time_of_pause = tu_timer::get_ticks();
1325
void NetStreamFfmpeg::unpausePlayback()
1327
if (!m_pause) // already not paused
1334
if (m_current_timestamp == 0)
1336
m_start_clock = tu_timer::get_ticks();
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;
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);
1353
NetStreamFfmpeg::bytesLoaded ()
1359
ret_val = _netCon->getBytesLoaded();
1367
NetStreamFfmpeg::bytesTotal ()
1373
ret_val = _netCon->getBytesTotal();
1380
} // gnash namespcae
1382
#endif // USE_FFMPEG