diff options
| author | trialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38> | 2010-01-06 20:12:30 +0000 |
|---|---|---|
| committer | trialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38> | 2010-01-06 20:12:30 +0000 |
| commit | 7683057b2a0927288461cd7ffba03cd79b3e61f6 (patch) | |
| tree | ba82832e8d5c147c29fb86d2886871fdac543730 /src/plugins/Input/ffmpeg | |
| parent | 7c912726598715813996ebd570805463136cd04b (diff) | |
| download | qmmp-7683057b2a0927288461cd7ffba03cd79b3e61f6.tar.gz qmmp-7683057b2a0927288461cd7ffba03cd79b3e61f6.tar.bz2 qmmp-7683057b2a0927288461cd7ffba03cd79b3e61f6.zip | |
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
Diffstat (limited to 'src/plugins/Input/ffmpeg')
| -rw-r--r-- | src/plugins/Input/ffmpeg/decoder_ffmpeg.cpp | 109 | ||||
| -rw-r--r-- | src/plugins/Input/ffmpeg/decoder_ffmpeg.h | 8 | ||||
| -rw-r--r-- | src/plugins/Input/ffmpeg/decoderffmpegfactory.cpp | 11 | ||||
| -rw-r--r-- | src/plugins/Input/ffmpeg/settingsdialog.ui | 86 |
4 files changed, 148 insertions, 66 deletions
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 <qmmp/decoder.h> +#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<FileInfo *> DecoderFFmpegFactory::createPlayList(const QString &fileName, bool useMetaData) @@ -104,9 +103,9 @@ QList<FileInfo *> 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 @@ -<ui version="4.0" > +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> <class>SettingsDialog</class> - <widget class="QDialog" name="SettingsDialog" > - <property name="geometry" > + <widget class="QDialog" name="SettingsDialog"> + <property name="geometry"> <rect> <x>0</x> <y>0</y> @@ -9,16 +10,25 @@ <height>298</height> </rect> </property> - <property name="windowTitle" > + <property name="windowTitle"> <string>FFmpeg Plugin Settings</string> </property> - <layout class="QGridLayout" name="gridLayout" > - <item row="1" column="0" > - <spacer name="horizontalSpacer" > - <property name="orientation" > + <layout class="QGridLayout" name="gridLayout"> + <property name="leftMargin"> + <number>6</number> + </property> + <property name="rightMargin"> + <number>6</number> + </property> + <property name="bottomMargin"> + <number>6</number> + </property> + <item row="1" column="0"> + <spacer name="horizontalSpacer"> + <property name="orientation"> <enum>Qt::Horizontal</enum> </property> - <property name="sizeHint" stdset="0" > + <property name="sizeHint" stdset="0"> <size> <width>178</width> <height>20</height> @@ -26,77 +36,77 @@ </property> </spacer> </item> - <item row="1" column="1" > - <widget class="QDialogButtonBox" name="buttonBox" > - <property name="sizePolicy" > - <sizepolicy vsizetype="Fixed" hsizetype="Maximum" > + <item row="1" column="1"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="standardButtons" > + <property name="standardButtons"> <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> </property> </widget> </item> - <item row="0" column="0" colspan="2" > - <widget class="QGroupBox" name="groupBox" > - <property name="title" > + <item row="0" column="0" colspan="2"> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> <string>Formats</string> </property> - <layout class="QVBoxLayout" name="verticalLayout" > + <layout class="QVBoxLayout" name="verticalLayout"> <item> - <widget class="QCheckBox" name="wmaCheckBox" > - <property name="text" > + <widget class="QCheckBox" name="wmaCheckBox"> + <property name="text"> <string>Windows Media Audio</string> </property> </widget> </item> <item> - <widget class="QCheckBox" name="apeCheckBox" > - <property name="text" > + <widget class="QCheckBox" name="apeCheckBox"> + <property name="text"> <string>Monkey's Audio</string> </property> </widget> </item> <item> - <widget class="QCheckBox" name="ttaCheckBox" > - <property name="text" > + <widget class="QCheckBox" name="ttaCheckBox"> + <property name="text"> <string>True Audio</string> </property> </widget> </item> <item> - <widget class="QCheckBox" name="alacCheckBox" > - <property name="text" > + <widget class="QCheckBox" name="alacCheckBox"> + <property name="text"> <string>ALAC (Apple Lossless Audio Codec)</string> </property> </widget> </item> <item> - <widget class="QCheckBox" name="aacCheckBox" > - <property name="text" > + <widget class="QCheckBox" name="aacCheckBox"> + <property name="text"> <string>ADTS AAC</string> </property> </widget> </item> <item> - <widget class="QCheckBox" name="mp3CheckBox" > - <property name="text" > + <widget class="QCheckBox" name="mp3CheckBox"> + <property name="text"> <string>MP3 (MPEG audio layer 3)</string> </property> </widget> </item> <item> - <widget class="QCheckBox" name="mp4CheckBox" > - <property name="text" > + <widget class="QCheckBox" name="mp4CheckBox"> + <property name="text"> <string>MPEG-4 AAC</string> </property> </widget> </item> <item> - <widget class="QCheckBox" name="raCheckBox" > - <property name="text" > + <widget class="QCheckBox" name="raCheckBox"> + <property name="text"> <string>RealAudio 1.0/2.0</string> </property> </widget> @@ -114,11 +124,11 @@ <receiver>SettingsDialog</receiver> <slot>accept()</slot> <hints> - <hint type="sourcelabel" > + <hint type="sourcelabel"> <x>214</x> <y>167</y> </hint> - <hint type="destinationlabel" > + <hint type="destinationlabel"> <x>103</x> <y>160</y> </hint> @@ -130,11 +140,11 @@ <receiver>SettingsDialog</receiver> <slot>reject()</slot> <hints> - <hint type="sourcelabel" > + <hint type="sourcelabel"> <x>269</x> <y>174</y> </hint> - <hint type="destinationlabel" > + <hint type="destinationlabel"> <x>148</x> <y>169</y> </hint> |
