aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortrialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38>2008-09-21 11:25:50 +0000
committertrialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38>2008-09-21 11:25:50 +0000
commit1d58bc219b471db64390a20f361921842efbf602 (patch)
tree9359e53dd4d52f8b364ef8305ca2249d5abfa43f
parente7ea59067e6c975a16926647376175f0f2ab2afa (diff)
downloadqmmp-1d58bc219b471db64390a20f361921842efbf602.tar.gz
qmmp-1d58bc219b471db64390a20f361921842efbf602.tar.bz2
qmmp-1d58bc219b471db64390a20f361921842efbf602.zip
enabled stream support
git-svn-id: http://svn.code.sf.net/p/qmmp-dev/code/trunk/qmmp@553 90c681e8-e032-0410-971d-27865f9a5e38
-rw-r--r--src/plugins/Input/mad/decoder_mad.cpp2
-rw-r--r--src/plugins/Input/mad/decodermadfactory.cpp2
-rw-r--r--src/plugins/Input/mad/decodermadfactory.h2
-rw-r--r--src/qmmp/decoder.cpp211
-rw-r--r--src/qmmp/decoder.h13
-rw-r--r--src/qmmp/decoderfactory.h19
-rw-r--r--src/qmmp/soundcore.cpp95
-rw-r--r--src/qmmp/soundcore.h4
-rw-r--r--src/qmmp/statehandler.cpp22
-rw-r--r--src/ui/aboutdialog.cpp2
-rw-r--r--src/ui/configdialog.cpp6
-rw-r--r--src/ui/mainwindow.cpp2
-rw-r--r--src/ui/pluginitem.cpp1
13 files changed, 226 insertions, 155 deletions
diff --git a/src/plugins/Input/mad/decoder_mad.cpp b/src/plugins/Input/mad/decoder_mad.cpp
index 941dcee8b..2cd8567a0 100644
--- a/src/plugins/Input/mad/decoder_mad.cpp
+++ b/src/plugins/Input/mad/decoder_mad.cpp
@@ -316,7 +316,7 @@ bool DecoderMAD::findHeader()
if (!result)
return FALSE;
- if (!is_vbr)
+ if (!is_vbr && !input()->isSequential())
{
double time = (input()->size() * 8.0) / (header.bitrate);
double timefrac = (double)time - ((long)(time));
diff --git a/src/plugins/Input/mad/decodermadfactory.cpp b/src/plugins/Input/mad/decodermadfactory.cpp
index 57d299f40..10afdefc4 100644
--- a/src/plugins/Input/mad/decodermadfactory.cpp
+++ b/src/plugins/Input/mad/decodermadfactory.cpp
@@ -93,7 +93,7 @@ const DecoderProperties DecoderMADFactory::properties() const
return properties;
}
-Decoder *DecoderMADFactory::create(QObject *parent, QIODevice *input, Output *output)
+Decoder *DecoderMADFactory::create(QObject *parent, QIODevice *input, Output *output, const QString &)
{
return new DecoderMAD(parent, this, input, output);
}
diff --git a/src/plugins/Input/mad/decodermadfactory.h b/src/plugins/Input/mad/decodermadfactory.h
index 5688adbe9..3b1a45818 100644
--- a/src/plugins/Input/mad/decodermadfactory.h
+++ b/src/plugins/Input/mad/decodermadfactory.h
@@ -42,7 +42,7 @@ public:
bool supports(const QString &source) const;
bool canDecode(QIODevice *input) const;
const DecoderProperties properties() const;
- Decoder *create(QObject *, QIODevice *, Output *);
+ Decoder *create(QObject *, QIODevice *, Output *, const QString &);
FileTag *createTag(const QString &source);
QObject* showDetails(QWidget *parent, const QString &path);
void showSettings(QWidget *parent);
diff --git a/src/qmmp/decoder.cpp b/src/qmmp/decoder.cpp
index 3d460e1ba..e5f7681d5 100644
--- a/src/qmmp/decoder.cpp
+++ b/src/qmmp/decoder.cpp
@@ -118,6 +118,99 @@ void Decoder::volume(int *l, int *r)
m_mutex.unlock();
}
+void Decoder::configure(quint32 srate, int chan, int bps)
+{
+ Effect* effect = 0;
+ foreach(effect, m_effects)
+ {
+ effect->configure(srate, chan, bps);
+ srate = effect->sampleRate();
+ chan = effect->channels();
+ bps = effect->bitsPerSample();
+ }
+ if (m_output)
+ m_output->configure(srate, chan, bps);
+}
+
+qint64 Decoder::produceSound(char *data, qint64 size, quint32 brate, int chan)
+{
+ ulong sz = size < blksize ? size : blksize;
+
+ if (m_useEQ)
+ {
+ if (!m_eqInited)
+ {
+ init_iir();
+ m_eqInited = TRUE;
+ }
+ iir((void*) data, sz, chan);
+ }
+ if (m_useVolume)
+ {
+ changeVolume(data, sz, chan);
+ }
+ char *out_data = data;
+ char *prev_data = data;
+ qint64 w = sz;
+ Effect* effect = 0;
+ foreach(effect, m_effects)
+ {
+ w = effect->process(prev_data, sz, &out_data);
+
+ if (w <= 0)
+ {
+ // copy data if plugin can not process it
+ w = sz;
+ out_data = new char[w];
+ memcpy(out_data, prev_data, w);
+ }
+ if (data != prev_data)
+ delete prev_data;
+ prev_data = out_data;
+ }
+
+ Buffer *b = output()->recycler()->get(w);
+
+ memcpy(b->data, out_data, w);
+
+ if (data != out_data)
+ delete out_data;
+
+ if (w < blksize + b->exceeding)
+ memset(b->data + w, 0, blksize + b->exceeding - w);
+
+ b->nbytes = w;// blksize;
+ b->rate = brate;
+
+ output()->recycler()->add();
+
+ size -= sz;
+ memmove(data, data + sz, size);
+ return sz;
+}
+
+void Decoder::finish()
+{
+ //output()->wait();
+ emit finished();
+}
+
+void Decoder::changeVolume(char *data, qint64 size, int chan)
+{
+ if (chan > 1)
+ for (qint64 i = 0; i < size/2; i+=2)
+ {
+ ((short*)data)[i]*= m_volLF/256.0;
+ ((short*)data)[i+1]*= m_volRF/256.0;
+ }
+ else
+ {
+ int l = qMax(m_volLF,m_volRF);
+ for (qint64 i = 0; i < size/2; i++)
+ ((short*)data)[i]*= l/256.0;
+ }
+}
+
// static methods
QList<DecoderFactory*> *Decoder::m_factories = 0;
QStringList Decoder::m_files;
@@ -185,7 +278,7 @@ QStringList Decoder::all()
return l;
}
-QStringList Decoder::decoderFiles()
+QStringList Decoder::files()
{
checkFactories();
return m_files;
@@ -207,7 +300,7 @@ bool Decoder::supports(const QString &source)
return FALSE;
}
-Decoder *Decoder::create(QObject *parent, const QString &source,
+/*Decoder *Decoder::create(QObject *parent, const QString &source,
QIODevice *input,
Output *output)
{
@@ -236,7 +329,7 @@ Decoder *Decoder::create(QObject *parent, const QString &source,
else
output->setStateHandler(decoder->stateHandler());
return decoder;
-}
+}*/
DecoderFactory *Decoder::findByPath(const QString& source)
{
@@ -276,8 +369,7 @@ DecoderFactory *Decoder::findByMime(const QString& type)
DecoderFactory *Decoder::findByContent(QIODevice *input)
{
checkFactories();
- DecoderFactory *fact;
- foreach(fact, *m_factories)
+ foreach(DecoderFactory *fact, *m_factories)
{
if (fact->canDecode(input) && isEnabled(fact))
{
@@ -288,6 +380,21 @@ DecoderFactory *Decoder::findByContent(QIODevice *input)
return 0;
}
+DecoderFactory *Decoder::findByURL(const QUrl &url)
+{
+ checkFactories();
+ foreach(DecoderFactory *fact, *m_factories)
+ {
+ if (fact->supports(url.path()) && isEnabled(fact) &&
+ fact->properties().protocols.split(" ").contains(url.scheme()))
+ {
+ return fact;
+ }
+ }
+ qDebug("Decoder: unable to find factory by url");
+ return 0;
+}
+
void Decoder::setEnabled(DecoderFactory* factory, bool enable)
{
checkFactories();
@@ -350,101 +457,9 @@ QStringList Decoder::nameFilters()
return filters;
}
-QList<DecoderFactory*> *Decoder::decoderFactories()
+QList<DecoderFactory*> *Decoder::factories()
{
checkFactories();
return m_factories;
}
-void Decoder::configure(quint32 srate, int chan, int bps)
-{
- Effect* effect = 0;
- foreach(effect, m_effects)
- {
- effect->configure(srate, chan, bps);
- srate = effect->sampleRate();
- chan = effect->channels();
- bps = effect->bitsPerSample();
- }
- if (m_output)
- m_output->configure(srate, chan, bps);
-}
-
-qint64 Decoder::produceSound(char *data, qint64 size, quint32 brate, int chan)
-{
- ulong sz = size < blksize ? size : blksize;
-
- if (m_useEQ)
- {
- if (!m_eqInited)
- {
- init_iir();
- m_eqInited = TRUE;
- }
- iir((void*) data,size,chan);
- }
- if (m_useVolume)
- {
- changeVolume(data, sz, chan);
- }
- char *out_data = data;
- char *prev_data = data;
- qint64 w = sz;
- Effect* effect = 0;
- foreach(effect, m_effects)
- {
- w = effect->process(prev_data, sz, &out_data);
-
- if (w <= 0)
- {
- // copy data if plugin can not procees it
- w = sz;
- out_data = new char[w];
- memcpy(out_data, prev_data, w);
- }
- if (data != prev_data)
- delete prev_data;
- prev_data = out_data;
- }
-
- Buffer *b = output()->recycler()->get(w);
-
- memcpy(b->data, out_data, w);
-
- if (data != out_data)
- delete out_data;
-
- if (w < blksize + b->exceeding)
- memset(b->data + w, 0, blksize + b->exceeding - w);
-
- b->nbytes = w;// blksize;
- b->rate = brate;
-
- output()->recycler()->add();
-
- size -= sz;
- memmove(data, data + sz, size);
- return sz;
-}
-
-void Decoder::finish()
-{
- //output()->wait();
- emit finished();
-}
-
-void Decoder::changeVolume(char *data, qint64 size, int chan)
-{
- if (chan > 1)
- for (qint64 i = 0; i < size/2; i+=2)
- {
- ((short*)data)[i]*= m_volLF/256.0;
- ((short*)data)[i+1]*= m_volRF/256.0;
- }
- else
- {
- int l = qMax(m_volLF,m_volRF);
- for (qint64 i = 0; i < size/2; i++)
- ((short*)data)[i]*= l/256.0;
- }
-}
diff --git a/src/qmmp/decoder.h b/src/qmmp/decoder.h
index d1f3818df..c74446916 100644
--- a/src/qmmp/decoder.h
+++ b/src/qmmp/decoder.h
@@ -13,6 +13,7 @@
#include <QWaitCondition>
#include <QObject>
#include <QStringList>
+#include <QUrl>
#include "filetag.h"
@@ -33,8 +34,8 @@ class Decoder : public QThread
{
Q_OBJECT
public:
- Decoder(QObject *parent, DecoderFactory *d,
- QIODevice *i, Output *o);
+ Decoder(QObject *parent, DecoderFactory *d, QIODevice *input = 0, Output *output = 0);
+
virtual ~Decoder();
// Standard Decoder API
@@ -61,21 +62,21 @@ public:
// static methods
static QStringList all();
static bool supports(const QString &);
- static Decoder *create(QObject *, const QString &, QIODevice *, Output *);
+ //static Decoder *create(QObject *, const QString &, QIODevice *, Output *);
static DecoderFactory *findByPath(const QString&);
static DecoderFactory *findByMime(const QString&);
static DecoderFactory *findByContent(QIODevice *);
+ static DecoderFactory *findByURL(const QUrl &url);
static FileTag *createTag(const QString&);
static QStringList filters();
static QStringList nameFilters();
- static QList<DecoderFactory*> *decoderFactories();
- static QStringList decoderFiles();
+ static QList<DecoderFactory*> *factories();
+ static QStringList files();
static void setEnabled(DecoderFactory* factory, bool enable = TRUE);
static bool isEnabled(DecoderFactory* factory);
signals:
void finished();
- //void stateChanged(const DecoderState&);
protected:
void configure(quint32 srate, int chan, int bps);
diff --git a/src/qmmp/decoderfactory.h b/src/qmmp/decoderfactory.h
index d67d1b564..954f597b2 100644
--- a/src/qmmp/decoderfactory.h
+++ b/src/qmmp/decoderfactory.h
@@ -32,16 +32,26 @@ class Decoder;
class Output;
class FileTag;
-struct DecoderProperties
+class DecoderProperties
{
+public:
+ DecoderProperties()
+ {
+ hasAbout = FALSE;
+ hasSettings = FALSE;
+ noInput = FALSE;
+ noOutput = FALSE;
+
+ }
QString name;
QString filter;
QString description;
QString contentType;
+ QString protocols;
bool hasAbout;
bool hasSettings;
- //bool streamSupport;
- //bool needInput;
+ bool noInput;
+ bool noOutput;
};
class DecoderFactory
@@ -51,7 +61,8 @@ public:
virtual bool supports(const QString &source) const = 0;
virtual bool canDecode(QIODevice *) const = 0;
virtual const DecoderProperties properties() const = 0;
- virtual Decoder *create(QObject *, QIODevice *, Output *) = 0;
+ virtual Decoder *create(QObject *, QIODevice *input = 0,
+ Output *output = 0, const QString &path = QString()) = 0;
virtual FileTag *createTag(const QString &source) = 0;
virtual QObject* showDetails(QWidget *parent, const QString &path) = 0;
virtual void showSettings(QWidget *parent) = 0;
diff --git a/src/qmmp/soundcore.cpp b/src/qmmp/soundcore.cpp
index be7c124d9..d390269e7 100644
--- a/src/qmmp/soundcore.cpp
+++ b/src/qmmp/soundcore.cpp
@@ -49,6 +49,7 @@ SoundCore::SoundCore(QObject *parent)
m_preamp = 0;
m_vis = 0;
m_parentWidget = 0;
+ m_factory = 0;
m_state = Qmmp::Stopped;
for (int i = 1; i < 10; ++i)
m_bands[i] = 0;
@@ -65,27 +66,57 @@ bool SoundCore::play(const QString &source)
stop();
if (m_state != Qmmp::Stopped) //clear error state
setState(Qmmp::Stopped);
- m_input = new QFile(source);
- m_output = Output::create(this);
- if (!m_output)
+
+ if (QFile::exists(source)) //local file
+ m_url = QUrl::fromLocalFile(source);
+ else
+ m_url = source;
+
+ m_factory = Decoder::findByURL(m_url);
+ if (m_factory)
+ return decode();
+
+ if (m_url.scheme() == "file")
{
- qWarning("SoundCore: unable to create output");
- setState(Qmmp::FatalError);
- return FALSE;
+ if ((m_factory = Decoder::findByPath(m_url.path())))
+ {
+ m_input = new QFile(m_url.path());
+ if (!m_input->open(QIODevice::ReadOnly))
+ {
+ qDebug("SoundCore: cannot open input");
+ stop();
+ setState(Qmmp::NormalError);
+ }
+ return decode();
+ }
+ else
+ {
+ qWarning("SoundCore: unsupported fileformat");
+ stop();
+ setState(Qmmp::NormalError);
+ return FALSE;
+ }
}
- if (!m_output->initialize())
+ if (m_url.scheme() == "http")
{
- qWarning("SoundCore: unable to initialize output");
- setState(Qmmp::FatalError);
- return FALSE;
+ m_input = new StreamReader(source, this);
+ connect(m_input, SIGNAL(bufferingProgress(int)), SIGNAL(bufferingProgress(int)));
+ connect(m_input, SIGNAL(titleChanged(const QString&)),
+ SIGNAL(titleChanged(const QString&)));
+ connect(m_input, SIGNAL(readyRead()),SLOT(decode()));
+ qobject_cast<StreamReader *>(m_input)->downloadFile();
+ return TRUE;
}
- m_source = source;
- return decode();
-
+ qWarning("SoundCore: unsupported fileformat");
+ stop();
+ setState(Qmmp::NormalError);
+ return FALSE;
}
void SoundCore::stop()
{
+ m_factory = 0;
+ m_url.clear();
if (m_decoder && m_decoder->isRunning())
{
m_decoder->mutex()->lock ();
@@ -292,9 +323,39 @@ void SoundCore::setState(Qmmp::State state)
bool SoundCore::decode()
{
- if (!m_input || !m_output)
- return FALSE;
- m_decoder = Decoder::create(this, m_source, m_input, m_output);
+ if (!m_factory)
+ {
+ if (!m_input->open(QIODevice::ReadOnly))
+ {
+ qDebug("SoundCore:: cannot open input");
+ setState(Qmmp::NormalError);
+ return FALSE;
+ }
+ if (!(m_factory = Decoder::findByContent(m_input)))
+ {
+ setState(Qmmp::NormalError);
+ return FALSE;
+ }
+ }
+ if (!m_factory->properties().noOutput)
+ {
+ m_output = Output::create(this);
+ if (!m_output)
+ {
+ qWarning("SoundCore: unable to create output");
+ setState(Qmmp::FatalError);
+ return FALSE;
+ }
+ if (!m_output->initialize())
+ {
+ qWarning("SoundCore: unable to initialize output");
+ delete m_output;
+ m_output = 0;
+ setState(Qmmp::FatalError);
+ return FALSE;
+ }
+ }
+ m_decoder = m_factory->create(this, m_input, m_output, m_url.path());
if (!m_decoder)
{
qWarning("SoundCore: unsupported fileformat");
@@ -313,6 +374,8 @@ bool SoundCore::decode()
connect(handler, SIGNAL(metaDataChanged ()), SIGNAL(metaDataChanged ()));
connect(handler, SIGNAL(stateChanged (Qmmp::State)), SLOT(setState(Qmmp::State)));
connect(m_decoder, SIGNAL(finished()), SIGNAL(finished()));
+ if (m_output)
+ m_output->setStateHandler(handler);
if (m_decoder->initialize())
{
diff --git a/src/qmmp/soundcore.h b/src/qmmp/soundcore.h
index 604ae8c65..a83a4f75a 100644
--- a/src/qmmp/soundcore.h
+++ b/src/qmmp/soundcore.h
@@ -1,6 +1,6 @@
/***************************************************************************
* Copyright (C) 2006-2008 by Ilya Kotov *
- * forkotov02\hotmail.ru *
+ * forkotov02@hotmail.ru *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
@@ -156,6 +156,8 @@ private slots:
private:
Decoder* m_decoder;
+ DecoderFactory* m_factory;
+ QUrl m_url;
Output* m_output;
QIODevice* m_input;
uint m_error;
diff --git a/src/qmmp/statehandler.cpp b/src/qmmp/statehandler.cpp
index 1bb1fb235..58fa9dea5 100644
--- a/src/qmmp/statehandler.cpp
+++ b/src/qmmp/statehandler.cpp
@@ -27,7 +27,6 @@ StateHandler::StateHandler(QObject *parent)
{
m_instance = this;
m_elapsed = -1;
- m_totalTime = 0;
m_bitrate = 0;
m_frequency = 0;
m_precision = 0;
@@ -55,11 +54,6 @@ void StateHandler::dispatch(qint64 elapsed,
m_elapsed = elapsed;
emit (elapsedChanged(elapsed));
}
- /*if (m_totalTime != totalTime)
- {
- m_totalTime = totalTime;
- emit (totalTimeChanged(totalTime));
- }*/
if (m_bitrate != bitrate)
{
m_bitrate = bitrate;
@@ -105,27 +99,11 @@ void StateHandler::dispatch(const Qmmp::State &state)
m_mutex.unlock();
}
-/*void StateHandler::dispatchTotalTime(qint64 totalTime)
-{
- m_mutex.lock();
- if (m_totalTime != totalTime)
- {
- m_totalTime = totalTime;
- emit (totalTimeChanged(totalTime));
- }
- m_mutex.unlock();
-}*/
-
qint64 StateHandler::elapsed()
{
return m_elapsed;
}
-qint64 StateHandler::totalTime()
-{
- return m_totalTime;
-}
-
int StateHandler::bitrate()
{
return m_bitrate;
diff --git a/src/ui/aboutdialog.cpp b/src/ui/aboutdialog.cpp
index 128f89bc0..87f0317b0 100644
--- a/src/ui/aboutdialog.cpp
+++ b/src/ui/aboutdialog.cpp
@@ -82,7 +82,7 @@ QString AboutDialog::loadAbout()
text.append("<p>"+getstringFromResource(tr(":txt/description_en.txt"))+"</p>");
text.append("<h5>"+tr("Input plugins:")+"</h5>");
text.append("<ul type=\"square\">");
- foreach(DecoderFactory *fact, *Decoder::decoderFactories())
+ foreach(DecoderFactory *fact, *Decoder::factories())
{
text.append("<li>");
text.append(fact->properties().name);
diff --git a/src/ui/configdialog.cpp b/src/ui/configdialog.cpp
index a27a8cb31..6b950d546 100644
--- a/src/ui/configdialog.cpp
+++ b/src/ui/configdialog.cpp
@@ -198,8 +198,8 @@ void ConfigDialog::loadPluginsInfo()
load input plugins information
*/
QList <DecoderFactory *> *decoders = 0;
- decoders = Decoder::decoderFactories();
- QStringList files = Decoder::decoderFiles();
+ decoders = Decoder::factories();
+ QStringList files = Decoder::files();
ui.inputPluginTable->setColumnCount ( 3 );
ui.inputPluginTable->verticalHeader()->hide();
ui.inputPluginTable->setHorizontalHeaderLabels ( QStringList()
@@ -413,7 +413,7 @@ void ConfigDialog::showPluginSettings()
case 0:
{
QList <DecoderFactory *> *decoders = 0;
- decoders = Decoder::decoderFactories();
+ decoders = Decoder::factories();
int row = ui.inputPluginTable->currentRow ();
if ( !decoders || row<0 )
return;
diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp
index fdf2e1bd7..e456183ed 100644
--- a/src/ui/mainwindow.cpp
+++ b/src/ui/mainwindow.cpp
@@ -202,7 +202,7 @@ void MainWindow::play()
if (m_core->play(s))
{
//display->setTime(0);
- qDebug("play");
+ //qDebug("play");
m_generalHandler->setTime(0);
//display->setDuration(m_core->totalTime());
}
diff --git a/src/ui/pluginitem.cpp b/src/ui/pluginitem.cpp
index bbfdab306..1d5b7a3d8 100644
--- a/src/ui/pluginitem.cpp
+++ b/src/ui/pluginitem.cpp
@@ -156,3 +156,4 @@ GeneralFactory *GeneralPluginItem::factory()
{
return m_factory;
}
+