aboutsummaryrefslogtreecommitdiff
path: root/src/plugins/Input/ffmpeg
diff options
context:
space:
mode:
authortrialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38>2010-01-06 20:12:30 +0000
committertrialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38>2010-01-06 20:12:30 +0000
commit7683057b2a0927288461cd7ffba03cd79b3e61f6 (patch)
treeba82832e8d5c147c29fb86d2886871fdac543730 /src/plugins/Input/ffmpeg
parent7c912726598715813996ebd570805463136cd04b (diff)
downloadqmmp-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.cpp109
-rw-r--r--src/plugins/Input/ffmpeg/decoder_ffmpeg.h8
-rw-r--r--src/plugins/Input/ffmpeg/decoderffmpegfactory.cpp11
-rw-r--r--src/plugins/Input/ffmpeg/settingsdialog.ui86
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>