diff options
author | Lev Zelenskiy <lev.zelenskiy@nokia.com> | 2012-02-24 12:50:32 +1000 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-02-24 06:00:41 +0100 |
commit | b56d3e70df4a5bf25a1be97213b5dc36bc5e6dbd (patch) | |
tree | e35fd301a0e7198609679c95e2374d4b4aa28e85 /src | |
parent | 0b8c6115cdb1ed7174b558daa00a19841a2d5a78 (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')
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 |