From 5672fa90e799f6cc2a54ea31213cbf5973eb7eee Mon Sep 17 00:00:00 2001 From: David Sansome Date: Sun, 6 Mar 2011 18:11:53 +0000 Subject: [PATCH] Wait for the gstreamer pipeline to be connected and in either the PAUSED or PLAYING state before trying to do the initial seek. This should stop the occasional "seek failed" messages when playing tracks. Fixes issue #1292 --- src/engines/gstenginepipeline.cpp | 42 +++++++++++++++++++++++++++++++ src/engines/gstenginepipeline.h | 10 +++++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/engines/gstenginepipeline.cpp b/src/engines/gstenginepipeline.cpp index 6aced2804..5c051583b 100644 --- a/src/engines/gstenginepipeline.cpp +++ b/src/engines/gstenginepipeline.cpp @@ -52,7 +52,11 @@ GstEnginePipeline::GstEnginePipeline(GstEngine* engine) end_offset_nanosec_(-1), next_beginning_offset_nanosec_(-1), next_end_offset_nanosec_(-1), + ignore_next_seek_(false), ignore_tags_(false), + pipeline_is_initialised_(false), + pipeline_is_connected_(false), + pending_seek_nanosec_(-1), volume_percent_(100), volume_modifier_(1.0), fader_(NULL), @@ -107,6 +111,7 @@ bool GstEnginePipeline::ReplaceDecodeBin(GstElement* new_bin) { uridecodebin_ = new_bin; segment_start_ = 0; segment_start_received_ = false; + pipeline_is_connected_ = false; gst_bin_add(GST_BIN(pipeline_), uridecodebin_); return true; @@ -275,6 +280,10 @@ gboolean GstEnginePipeline::BusCallback(GstBus*, GstMessage* msg, gpointer self) instance->TagMessageReceived(msg); break; + case GST_MESSAGE_STATE_CHANGED: + instance->StateChangedMessageReceived(msg); + break; + default: break; } @@ -301,6 +310,10 @@ GstBusSyncReply GstEnginePipeline::BusCallbackSync(GstBus*, GstMessage* msg, gpo instance->ElementMessageReceived(msg); break; + case GST_MESSAGE_STATE_CHANGED: + instance->StateChangedMessageReceived(msg); + break; + default: break; } @@ -375,6 +388,23 @@ QString GstEnginePipeline::ParseTag(GstTagList* list, const char* tag) const { return ret.trimmed(); } +void GstEnginePipeline::StateChangedMessageReceived(GstMessage* msg) { + GstState old_state, new_state, pending; + gst_message_parse_state_changed(msg, &old_state, &new_state, &pending); + + if (!pipeline_is_initialised_ && (new_state == GST_STATE_PAUSED || new_state == GST_STATE_PLAYING)) { + pipeline_is_initialised_ = true; + if (pending_seek_nanosec_ != -1 && pipeline_is_connected_) { + QMetaObject::invokeMethod(this, "Seek", Qt::QueuedConnection, + Q_ARG(qint64, pending_seek_nanosec_)); + } + } + + if (pipeline_is_initialised_ && new_state != GST_STATE_PAUSED && new_state != GST_STATE_PLAYING) { + pipeline_is_initialised_ = false; + } +} + void GstEnginePipeline::NewPadCallback(GstElement*, GstPad* pad, gpointer self) { GstEnginePipeline* instance = reinterpret_cast(self); @@ -388,6 +418,12 @@ void GstEnginePipeline::NewPadCallback(GstElement*, GstPad* pad, gpointer self) gst_pad_link(pad, audiopad); gst_object_unref(audiopad); + + instance->pipeline_is_connected_ = true; + if (instance->pending_seek_nanosec_ != -1 && instance->pipeline_is_initialised_) { + QMetaObject::invokeMethod(instance, "Seek", Qt::QueuedConnection, + Q_ARG(qint64, instance->pending_seek_nanosec_)); + } } @@ -526,6 +562,12 @@ bool GstEnginePipeline::Seek(qint64 nanosec) { return true; } + if (!pipeline_is_connected_ || !pipeline_is_initialised_) { + pending_seek_nanosec_ = nanosec; + return true; + } + + pending_seek_nanosec_ = -1; return gst_element_seek_simple(pipeline_, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, nanosec); } diff --git a/src/engines/gstenginepipeline.h b/src/engines/gstenginepipeline.h index f6109f41c..0cdbd2658 100644 --- a/src/engines/gstenginepipeline.h +++ b/src/engines/gstenginepipeline.h @@ -59,7 +59,7 @@ class GstEnginePipeline : public QObject { // Control the music playback QFuture SetState(GstState state); - bool Seek(qint64 nanosec); + Q_INVOKABLE bool Seek(qint64 nanosec); void SetEqualizerEnabled(bool enabled); void SetEqualizerParams(int preamp, const QList& band_gains); void SetVolume(int percent); @@ -110,6 +110,7 @@ class GstEnginePipeline : public QObject { void TagMessageReceived(GstMessage*); void ErrorMessageReceived(GstMessage*); void ElementMessageReceived(GstMessage*); + void StateChangedMessageReceived(GstMessage*); QString ParseTag(GstTagList* list, const char* tag) const; bool Init(); @@ -185,6 +186,13 @@ class GstEnginePipeline : public QObject { // callers can pick it up after the state change to PLAYING fails. QUrl redirect_url_; + // Seeking while the pipeline is in the READY state doesn't work, so we have + // to wait until it goes to PAUSED or PLAYING. + // Also we have to wait for the decodebin to be connected. + bool pipeline_is_initialised_; + bool pipeline_is_connected_; + qint64 pending_seek_nanosec_; + int volume_percent_; qreal volume_modifier_;