summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLev Zelenskiy <lev.zelenskiy@nokia.com>2012-02-24 12:50:32 +1000
committerQt by Nokia <qt-info@nokia.com>2012-02-24 06:00:41 +0100
commitb56d3e70df4a5bf25a1be97213b5dc36bc5e6dbd (patch)
treee35fd301a0e7198609679c95e2374d4b4aa28e85 /src
parent0b8c6115cdb1ed7174b558daa00a19841a2d5a78 (diff)
Changes to GStreamer backend for audio decoder.
Removed WaitingState. New signals: finished(), positionChanged(), durationChanged(). New methods: position(), duration(). A parameter removed from read() method. Unit tests updated. Change-Id: Ie9d8a2804285c5542e592cce69963adbdf6ebfb8 Reviewed-by: Jonas Rabbe <jonas.rabbe@nokia.com> Reviewed-by: Michael Goddard <michael.goddard@nokia.com>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/gstreamer/audiodecoder/qgstreameraudiodecodercontrol.cpp18
-rw-r--r--src/plugins/gstreamer/audiodecoder/qgstreameraudiodecodercontrol.h5
-rw-r--r--src/plugins/gstreamer/audiodecoder/qgstreameraudiodecodersession.cpp103
-rw-r--r--src/plugins/gstreamer/audiodecoder/qgstreameraudiodecodersession.h19
4 files changed, 124 insertions, 21 deletions
diff --git a/src/plugins/gstreamer/audiodecoder/qgstreameraudiodecodercontrol.cpp b/src/plugins/gstreamer/audiodecoder/qgstreameraudiodecodercontrol.cpp
index 4668a39bb..1d4de00e4 100644
--- a/src/plugins/gstreamer/audiodecoder/qgstreameraudiodecodercontrol.cpp
+++ b/src/plugins/gstreamer/audiodecoder/qgstreameraudiodecodercontrol.cpp
@@ -64,6 +64,9 @@ QGstreamerAudioDecoderControl::QGstreamerAudioDecoderControl(QGstreamerAudioDeco
connect(m_session, SIGNAL(formatChanged(QAudioFormat)), this, SIGNAL(formatChanged(QAudioFormat)));
connect(m_session, SIGNAL(sourceChanged()), this, SIGNAL(sourceChanged()));
connect(m_session, SIGNAL(stateChanged(QAudioDecoder::State)), this, SIGNAL(stateChanged(QAudioDecoder::State)));
+ connect(m_session, SIGNAL(finished()), this, SIGNAL(finished()));
+ connect(m_session, SIGNAL(positionChanged(qint64)), this, SIGNAL(positionChanged(qint64)));
+ connect(m_session, SIGNAL(durationChanged(qint64)), this, SIGNAL(durationChanged(qint64)));
}
QGstreamerAudioDecoderControl::~QGstreamerAudioDecoderControl()
@@ -73,7 +76,7 @@ QGstreamerAudioDecoderControl::~QGstreamerAudioDecoderControl()
QAudioDecoder::State QGstreamerAudioDecoderControl::state() const
{
- return m_session->state();
+ return m_session->pendingState();
}
QString QGstreamerAudioDecoderControl::sourceFilename() const
@@ -116,9 +119,9 @@ void QGstreamerAudioDecoderControl::setAudioFormat(const QAudioFormat &format)
m_session->setAudioFormat(format);
}
-QAudioBuffer QGstreamerAudioDecoderControl::read(bool *ok)
+QAudioBuffer QGstreamerAudioDecoderControl::read()
{
- return m_session->read(ok);
+ return m_session->read();
}
bool QGstreamerAudioDecoderControl::bufferAvailable() const
@@ -126,5 +129,14 @@ bool QGstreamerAudioDecoderControl::bufferAvailable() const
return m_session->bufferAvailable();
}
+qint64 QGstreamerAudioDecoderControl::position() const
+{
+ return m_session->position();
+}
+
+qint64 QGstreamerAudioDecoderControl::duration() const
+{
+ return m_session->duration();
+}
QT_END_NAMESPACE
diff --git a/src/plugins/gstreamer/audiodecoder/qgstreameraudiodecodercontrol.h b/src/plugins/gstreamer/audiodecoder/qgstreameraudiodecodercontrol.h
index 40699b697..bee39aa2d 100644
--- a/src/plugins/gstreamer/audiodecoder/qgstreameraudiodecodercontrol.h
+++ b/src/plugins/gstreamer/audiodecoder/qgstreameraudiodecodercontrol.h
@@ -80,9 +80,12 @@ public:
QAudioFormat audioFormat() const;
void setAudioFormat(const QAudioFormat &format);
- QAudioBuffer read(bool *ok);
+ QAudioBuffer read();
bool bufferAvailable() const;
+ qint64 position() const;
+ qint64 duration() const;
+
private:
// Stuff goes here
diff --git a/src/plugins/gstreamer/audiodecoder/qgstreameraudiodecodersession.cpp b/src/plugins/gstreamer/audiodecoder/qgstreameraudiodecodersession.cpp
index 518bf7780..8815819ef 100644
--- a/src/plugins/gstreamer/audiodecoder/qgstreameraudiodecodersession.cpp
+++ b/src/plugins/gstreamer/audiodecoder/qgstreameraudiodecodersession.cpp
@@ -87,7 +87,10 @@ QGstreamerAudioDecoderSession::QGstreamerAudioDecoderSession(QObject *parent)
m_appSrc(0),
#endif
mDevice(0),
- m_buffersAvailable(0)
+ m_buffersAvailable(0),
+ m_position(-1),
+ m_duration(-1),
+ m_durationQueries(0)
{
// Create pipeline here
m_playbin = gst_element_factory_make("playbin2", NULL);
@@ -160,7 +163,9 @@ bool QGstreamerAudioDecoderSession::processBusMessage(const QGstreamerMessage &m
{
GstMessage* gm = message.rawMessage();
if (gm) {
- if (GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_playbin)) {
+ if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_DURATION) {
+ updateDuration();
+ } else if (GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_playbin)) {
switch (GST_MESSAGE_TYPE(gm)) {
case GST_MESSAGE_STATE_CHANGED:
{
@@ -180,30 +185,39 @@ bool QGstreamerAudioDecoderSession::processBusMessage(const QGstreamerMessage &m
.arg(states[pending]) << "internal" << m_state;
#endif
+ QAudioDecoder::State prevState = m_state;
+
switch (newState) {
case GST_STATE_VOID_PENDING:
case GST_STATE_NULL:
- if (m_state != QAudioDecoder::StoppedState)
- emit stateChanged(m_state = QAudioDecoder::StoppedState);
+ m_state = QAudioDecoder::StoppedState;
break;
case GST_STATE_READY:
- if (m_state != QAudioDecoder::StoppedState)
- emit stateChanged(m_state = QAudioDecoder::StoppedState);
+ m_state = QAudioDecoder::StoppedState;
break;
case GST_STATE_PLAYING:
- if (m_state != QAudioDecoder::DecodingState)
- emit stateChanged(m_state = QAudioDecoder::DecodingState);
+ m_state = QAudioDecoder::DecodingState;
break;
case GST_STATE_PAUSED:
- if (m_state != QAudioDecoder::WaitingState)
- emit stateChanged(m_state = QAudioDecoder::WaitingState);
+ m_state = QAudioDecoder::DecodingState;
+
+ //gstreamer doesn't give a reliable indication the duration
+ //information is ready, GST_MESSAGE_DURATION is not sent by most elements
+ //the duration is queried up to 5 times with increasing delay
+ m_durationQueries = 5;
+ updateDuration();
break;
}
+
+ if (prevState != m_state)
+ emit stateChanged(m_state);
}
break;
case GST_MESSAGE_EOS:
- emit stateChanged(m_state = QAudioDecoder::StoppedState);
+ m_pendingState = m_state = QAudioDecoder::StoppedState;
+ emit finished();
+ emit stateChanged(m_state);
break;
case GST_MESSAGE_ERROR: {
@@ -364,6 +378,16 @@ void QGstreamerAudioDecoderSession::stop()
emit bufferAvailableChanged(false);
}
+ if (m_position != -1) {
+ m_position = -1;
+ emit positionChanged(m_position);
+ }
+
+ if (m_duration != -1) {
+ m_duration = -1;
+ emit durationChanged(m_duration);
+ }
+
if (oldState != m_state)
emit stateChanged(m_state);
}
@@ -382,7 +406,7 @@ void QGstreamerAudioDecoderSession::setAudioFormat(const QAudioFormat &format)
}
}
-QAudioBuffer QGstreamerAudioDecoderSession::read(bool *ok)
+QAudioBuffer QGstreamerAudioDecoderSession::read()
{
QAudioBuffer audioBuffer;
@@ -407,13 +431,17 @@ QAudioBuffer QGstreamerAudioDecoderSession::read(bool *ok)
if (format.isValid()) {
// XXX At the moment we have to copy data from GstBuffer into QAudioBuffer.
// We could improve performance by implementing QAbstractAudioBuffer for GstBuffer.
- audioBuffer = QAudioBuffer(QByteArray((const char*)buffer->data, buffer->size), format);
+ qint64 position = getPositionFromBuffer(buffer);
+ audioBuffer = QAudioBuffer(QByteArray((const char*)buffer->data, buffer->size), format, position);
+ position /= 1000; // convert to milliseconds
+ if (position != m_position) {
+ m_position = position;
+ emit positionChanged(m_position);
+ }
}
gst_buffer_unref(buffer);
}
- if (ok)
- *ok = audioBuffer.isValid();
return audioBuffer;
}
@@ -423,6 +451,16 @@ bool QGstreamerAudioDecoderSession::bufferAvailable() const
return m_buffersAvailable;
}
+qint64 QGstreamerAudioDecoderSession::position() const
+{
+ return m_position;
+}
+
+qint64 QGstreamerAudioDecoderSession::duration() const
+{
+ return m_duration;
+}
+
void QGstreamerAudioDecoderSession::processInvalidMedia(QAudioDecoder::Error errorCode, const QString& errorString)
{
stop();
@@ -492,4 +530,39 @@ void QGstreamerAudioDecoderSession::removeAppSink()
m_appSink = 0;
}
+void QGstreamerAudioDecoderSession::updateDuration()
+{
+ GstFormat format = GST_FORMAT_TIME;
+ gint64 gstDuration = 0;
+ int duration = -1;
+
+ if (m_playbin && gst_element_query_duration(m_playbin, &format, &gstDuration))
+ duration = gstDuration / 1000000;
+
+ if (m_duration != duration) {
+ m_duration = duration;
+ emit durationChanged(m_duration);
+ }
+
+ if (m_duration > 0)
+ m_durationQueries = 0;
+
+ if (m_durationQueries > 0) {
+ //increase delay between duration requests
+ int delay = 25 << (5 - m_durationQueries);
+ QTimer::singleShot(delay, this, SLOT(updateDuration()));
+ m_durationQueries--;
+ }
+}
+
+qint64 QGstreamerAudioDecoderSession::getPositionFromBuffer(GstBuffer* buffer)
+{
+ qint64 position = GST_BUFFER_TIMESTAMP(buffer);
+ if (position >= 0)
+ position = position / G_GINT64_CONSTANT(1000); // microseconds
+ else
+ position = -1;
+ return position;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/gstreamer/audiodecoder/qgstreameraudiodecodersession.h b/src/plugins/gstreamer/audiodecoder/qgstreameraudiodecodersession.h
index 2ec6e34a4..2c491cbaa 100644
--- a/src/plugins/gstreamer/audiodecoder/qgstreameraudiodecodersession.h
+++ b/src/plugins/gstreamer/audiodecoder/qgstreameraudiodecodersession.h
@@ -94,9 +94,12 @@ public:
QAudioFormat audioFormat() const;
void setAudioFormat(const QAudioFormat &format);
- QAudioBuffer read(bool *ok);
+ QAudioBuffer read();
bool bufferAvailable() const;
+ qint64 position() const;
+ qint64 duration() const;
+
static GstFlowReturn new_buffer(GstAppSink *sink, gpointer user_data);
signals:
@@ -108,14 +111,21 @@ signals:
void bufferReady();
void bufferAvailableChanged(bool available);
+ void finished();
-private:
+ void positionChanged(qint64 position);
+ void durationChanged(qint64 duration);
+
+private slots:
+ void updateDuration();
+private:
void setAudioFlags(bool wantNativeAudio);
void addAppSink();
void removeAppSink();
void processInvalidMedia(QAudioDecoder::Error errorCode, const QString& errorString);
+ static qint64 getPositionFromBuffer(GstBuffer* buffer);
QAudioDecoder::State m_state;
QAudioDecoder::State m_pendingState;
@@ -136,6 +146,11 @@ private:
mutable QMutex m_buffersMutex;
int m_buffersAvailable;
+
+ qint64 m_position;
+ qint64 m_duration;
+
+ int m_durationQueries;
};
QT_END_NAMESPACE