From 7683057b2a0927288461cd7ffba03cd79b3e61f6 Mon Sep 17 00:00:00 2001 From: trialuser02 Date: Wed, 6 Jan 2010 20:12:30 +0000 Subject: improved ffmpeg plugin: added stream input, fixed some bugs git-svn-id: http://svn.code.sf.net/p/qmmp-dev/code/trunk/qmmp@1483 90c681e8-e032-0410-971d-27865f9a5e38 --- src/plugins/Input/ffmpeg/decoder_ffmpeg.cpp | 109 ++++++++++++++++++---- src/plugins/Input/ffmpeg/decoder_ffmpeg.h | 8 +- src/plugins/Input/ffmpeg/decoderffmpegfactory.cpp | 11 +-- src/plugins/Input/ffmpeg/settingsdialog.ui | 86 +++++++++-------- 4 files changed, 148 insertions(+), 66 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/Input/ffmpeg/decoder_ffmpeg.cpp b/src/plugins/Input/ffmpeg/decoder_ffmpeg.cpp index 71a3c1e87..012abd36a 100644 --- a/src/plugins/Input/ffmpeg/decoder_ffmpeg.cpp +++ b/src/plugins/Input/ffmpeg/decoder_ffmpeg.cpp @@ -27,10 +27,45 @@ #include "decoder_ffmpeg.h" +// callbacks + +static int ffmpeg_read(void *data, uint8_t *buf, int size) +{ + DecoderFFmpeg *d = (DecoderFFmpeg*)data; + return (int)d->input()->read((char*)buf, size); +} + +static int64_t ffmpeg_seek(void *data, int64_t offset, int whence) +{ + DecoderFFmpeg *d = (DecoderFFmpeg*)data; + int64_t absolute_pos = 0; + /*if(d->input()->isSequential()) + return -1;*/ + switch( whence ) + { + case AVSEEK_SIZE: + return d->input()->size(); + case SEEK_SET: + absolute_pos = offset; + break; + case SEEK_CUR: + absolute_pos = d->input()->pos() + offset; + break; + case SEEK_END: + absolute_pos = d->input()->size() - offset; + default: + return -1; + } + if(absolute_pos < 0 || absolute_pos > d->input()->size()) + return -1; + return d->input()->seek(absolute_pos); +} + + // Decoder class -DecoderFFmpeg::DecoderFFmpeg(const QString &path) - : Decoder() +DecoderFFmpeg::DecoderFFmpeg(const QString &path, QIODevice *i) + : Decoder(i) { m_bitrate = 0; m_skip = FALSE; @@ -39,9 +74,12 @@ DecoderFFmpeg::DecoderFFmpeg(const QString &path) m_path = path; m_temp_pkt.size = 0; m_pkt.size = 0; + m_pkt.data = 0; m_output_buf = 0; m_output_at = 0; m_skipBytes = 0; + av_init_packet(&m_pkt); + av_init_packet(&m_temp_pkt); } @@ -50,8 +88,8 @@ DecoderFFmpeg::~DecoderFFmpeg() m_bitrate = 0; m_temp_pkt.size = 0; if (ic) - av_close_input_file(ic); - if(m_pkt.data) + av_close_input_stream(ic); + if(m_pkt.data) av_free_packet(&m_pkt); if(m_output_buf) delete [] m_output_buf; @@ -63,21 +101,48 @@ bool DecoderFFmpeg::initialize() m_skip = FALSE; m_totalTime = 0; m_seekTime = -1; - - avcodec_init(); - avcodec_register_all(); av_register_all(); - AVCodec *codec; - if (av_open_input_file(&ic, m_path.toLocal8Bit(), NULL,0, NULL) < 0) + AVProbeData pd; + uint8_t buf[2048]; + pd.filename = m_path.toLocal8Bit().constData(); + pd.buf_size = input()->peek((char*)buf, sizeof(buf)); + pd.buf = buf; + if(pd.buf_size < 2048) + return FALSE; + AVInputFormat *fmt = av_probe_input_format(&pd, 1); + if(!fmt) { - qDebug("DecoderFFmpeg: cannot open input file"); + qWarning("DecoderFFmpeg: usupported format"); return FALSE; } + qDebug("DecoderFFmpeg: detected format: %s", fmt->long_name); + + init_put_byte(&m_stream, m_input_buf, INPUT_BUFFER_SIZE, + 0, this, ffmpeg_read, NULL, ffmpeg_seek); + + m_stream.is_streamed = input()->isSequential(); + m_stream.max_packet_size = INPUT_BUFFER_SIZE; + + + AVFormatParameters ap; + memset(&ap, 0, sizeof(ap)); + + if(av_open_input_stream(&ic, &m_stream, m_path.toLocal8Bit(), + fmt, &ap) != 0) + { + qDebug("DecoderFFmpeg: av_open_input_stream() failed"); + return FALSE; + } + + AVCodec *codec; av_find_stream_info(ic); - av_read_play(ic); + if(ic->pb) + ic->pb->eof_reached = 0; + ic->flags |= AVFMT_FLAG_GENPTS; + av_read_play(ic); for (wma_idx = 0; wma_idx < (int)ic->nb_streams; wma_idx++) { c = ic->streams[wma_idx]->codec; @@ -90,14 +155,19 @@ bool DecoderFFmpeg::initialize() c->channels = 2; dump_format(ic,0,0,0); - //dump_stream_info(ic); - codec = avcodec_find_decoder(c->codec_id); - if (!codec) return FALSE; - if (avcodec_open(c, codec) < 0) + if (!codec) + { + qWarning("DecoderFFmpeg: unsupported codec for output stream"); return FALSE; + } + if (avcodec_open(c, codec) < 0) + { + qWarning("DecoderFFmpeg: error while opening codec for output stream"); + return FALSE; + } m_totalTime = ic->duration * 1000 / AV_TIME_BASE; m_output_buf = new uint8_t[AVCODEC_MAX_AUDIO_FRAME_SIZE*sizeof(int16_t) + Qmmp::globalBufferSize()]; configure(c->sample_rate, c->channels, 16); @@ -112,7 +182,6 @@ qint64 DecoderFFmpeg::totalTime() return m_totalTime; } - int DecoderFFmpeg::bitrate() { return m_bitrate; @@ -120,6 +189,7 @@ int DecoderFFmpeg::bitrate() qint64 DecoderFFmpeg::read(char *audio, qint64 maxSize) { + m_skipBytes = 0; if (m_skip) { @@ -136,7 +206,6 @@ qint64 DecoderFFmpeg::read(char *audio, qint64 maxSize) memcpy(audio, m_output_buf, len); m_output_at -= len; memmove(m_output_buf, m_output_buf + len, m_output_at-m_skipBytes); - return len; } @@ -164,7 +233,7 @@ qint64 DecoderFFmpeg::ffmpeg_decode(uint8_t *audio) void DecoderFFmpeg::seek(qint64 pos) { - int64_t timestamp = int64_t(pos)*AV_TIME_BASE/1000; + int64_t timestamp = int64_t(pos)*AV_TIME_BASE/1000; if (ic->start_time != (qint64)AV_NOPTS_VALUE) timestamp += ic->start_time; m_seekTime = timestamp; @@ -233,11 +302,11 @@ void DecoderFFmpeg::fillBuffer() m_output_at = ffmpeg_decode(m_output_buf); #endif - if(m_output_at < 0) { m_output_at = 0; - break; + m_temp_pkt.size = 0; + continue; } else if(m_output_at == 0) { diff --git a/src/plugins/Input/ffmpeg/decoder_ffmpeg.h b/src/plugins/Input/ffmpeg/decoder_ffmpeg.h index 624dcd4b3..5dc3085b9 100644 --- a/src/plugins/Input/ffmpeg/decoder_ffmpeg.h +++ b/src/plugins/Input/ffmpeg/decoder_ffmpeg.h @@ -42,10 +42,12 @@ extern "C"{ } #include +#define INPUT_BUFFER_SIZE 16384 + class DecoderFFmpeg : public Decoder { public: - DecoderFFmpeg(const QString &); + DecoderFFmpeg(const QString &, QIODevice *i); virtual ~DecoderFFmpeg(); // Standard Decoder API @@ -70,11 +72,13 @@ private: AVPacket m_pkt; AVPacket m_temp_pkt; + ByteIOContext m_stream; uint8_t *m_output_buf; qint64 m_output_at; + uchar m_input_buf[INPUT_BUFFER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE]; int64_t m_seekTime; - qint64 m_skipBytes; + qint64 m_skipBytes; }; diff --git a/src/plugins/Input/ffmpeg/decoderffmpegfactory.cpp b/src/plugins/Input/ffmpeg/decoderffmpegfactory.cpp index ad4ea9e95..5af4e41d6 100644 --- a/src/plugins/Input/ffmpeg/decoderffmpegfactory.cpp +++ b/src/plugins/Input/ffmpeg/decoderffmpegfactory.cpp @@ -87,15 +87,14 @@ const DecoderProperties DecoderFFmpegFactory::properties() const properties.shortName = "ffmpeg"; properties.hasAbout = TRUE; properties.hasSettings = TRUE; - properties.noInput = TRUE; - properties.protocols = "file"; + properties.noInput = FALSE; + //properties.protocols = "file"; return properties; } Decoder *DecoderFFmpegFactory::create(const QString &path, QIODevice *input) { - Q_UNUSED(input); - return new DecoderFFmpeg(path); + return new DecoderFFmpeg(path, input); } QList DecoderFFmpegFactory::createPlayList(const QString &fileName, bool useMetaData) @@ -104,9 +103,9 @@ QList DecoderFFmpegFactory::createPlayList(const QString &fileName, avcodec_init(); avcodec_register_all(); av_register_all(); - AVFormatContext *in; + AVFormatContext *in = 0; - if (av_open_input_file(&in, fileName.toLocal8Bit(), NULL,0, NULL) < 0) + if (av_open_input_file(&in, fileName.toLocal8Bit(), 0, 0, 0) < 0) { qDebug("DecoderFFmpegFactory: unable to open file"); return list; diff --git a/src/plugins/Input/ffmpeg/settingsdialog.ui b/src/plugins/Input/ffmpeg/settingsdialog.ui index 64f30ba0c..958251d8e 100644 --- a/src/plugins/Input/ffmpeg/settingsdialog.ui +++ b/src/plugins/Input/ffmpeg/settingsdialog.ui @@ -1,7 +1,8 @@ - + + SettingsDialog - - + + 0 0 @@ -9,16 +10,25 @@ 298 - + FFmpeg Plugin Settings - - - - + + + 6 + + + 6 + + + 6 + + + + Qt::Horizontal - + 178 20 @@ -26,77 +36,77 @@ - - - - + + + + 0 0 - + QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - + + + Formats - + - - + + Windows Media Audio - - + + Monkey's Audio - - + + True Audio - - + + ALAC (Apple Lossless Audio Codec) - - + + ADTS AAC - - + + MP3 (MPEG audio layer 3) - - + + MPEG-4 AAC - - + + RealAudio 1.0/2.0 @@ -114,11 +124,11 @@ SettingsDialog accept() - + 214 167 - + 103 160 @@ -130,11 +140,11 @@ SettingsDialog reject() - + 269 174 - + 148 169 -- cgit v1.2.3-13-gbd6f