diff --git a/src/core/songloader.cpp b/src/core/songloader.cpp index 0a28149c9..f8879cb92 100644 --- a/src/core/songloader.cpp +++ b/src/core/songloader.cpp @@ -404,7 +404,8 @@ SongLoader::Result SongLoader::LoadRemote() { // Create the source element automatically based on the URL GstElement* source = gst_element_make_from_uri( - GST_URI_SRC, url_.toEncoded().constData(), nullptr, nullptr); + GST_URI_SRC, Utilities::GetUriForGstreamer(url_).constData(), + nullptr, nullptr); if (!source) { qLog(Warning) << "Couldn't create gstreamer source element for" << url_.toString(); diff --git a/src/core/utilities.cpp b/src/core/utilities.cpp index 84cc2cd4d..fdad77dbf 100644 --- a/src/core/utilities.cpp +++ b/src/core/utilities.cpp @@ -741,6 +741,17 @@ QString FiddleFileExtension(const QString& filename, return PathWithoutFilenameExtension(filename) + "." + new_extension; } +QByteArray GetUriForGstreamer(const QUrl& url) { + if (url.scheme() == "file") { + QString local_file = url.toLocalFile(); + if (local_file.indexOf("//") == 0) { + // Exclude / from encoding. + return QByteArray("file://") + QUrl::toPercentEncoding(local_file, "/"); + } + } + return url.toEncoded(); +} + } // namespace Utilities ScopedWCharArray::ScopedWCharArray(const QString& str) diff --git a/src/core/utilities.h b/src/core/utilities.h index ca44a11f9..42940597f 100644 --- a/src/core/utilities.h +++ b/src/core/utilities.h @@ -123,6 +123,10 @@ QString PathWithoutFilenameExtension(const QString& filename); QString FiddleFileExtension(const QString& filename, const QString& new_extension); +// Fix URLs for Gstreamer, specifically those for network file paths that begin +// with //. +QByteArray GetUriForGstreamer(const QUrl& url); + enum ConfigPath { Path_Root, Path_Icons, diff --git a/src/engines/gstengine.cpp b/src/engines/gstengine.cpp index c9ba65a04..b768d426e 100644 --- a/src/engines/gstengine.cpp +++ b/src/engines/gstengine.cpp @@ -368,29 +368,13 @@ void GstEngine::StartPreloading(const QUrl& url, bool force_stop_at_end, qint64 beginning_nanosec, qint64 end_nanosec) { EnsureInitialised(); - QUrl gst_url = FixupUrl(url); - // No crossfading, so we can just queue the new URL in the existing // pipeline and get gapless playback (hopefully) if (current_pipeline_) - current_pipeline_->SetNextUrl(gst_url, beginning_nanosec, + current_pipeline_->SetNextUrl(url, beginning_nanosec, force_stop_at_end ? end_nanosec : 0); } -QUrl GstEngine::FixupUrl(const QUrl& url) { - QUrl copy = url; - - // It's a file:// url with a hostname set. QUrl::fromLocalFile does this - // when given a \\host\share\file path on Windows. Munge it back into a - // path that gstreamer will recognise. - if (url.scheme() == "file" && !url.host().isEmpty()) { - copy.setPath("//" + copy.host() + copy.path()); - copy.setHost(QString()); - } - - return copy; -} - bool GstEngine::Load(const QUrl& url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) { @@ -399,8 +383,6 @@ bool GstEngine::Load(const QUrl& url, Engine::TrackChangeFlags change, Engine::Base::Load(url, change, force_stop_at_end, beginning_nanosec, end_nanosec); - QUrl gst_url = FixupUrl(url); - bool crossfade = current_pipeline_ && ((crossfade_enabled_ && change & Engine::Manual) || (autocrossfade_enabled_ && change & Engine::Auto) || @@ -411,7 +393,7 @@ bool GstEngine::Load(const QUrl& url, Engine::TrackChangeFlags change, !crossfade_same_album_) crossfade = false; - if (!crossfade && current_pipeline_ && current_pipeline_->url() == gst_url && + if (!crossfade && current_pipeline_ && current_pipeline_->url() == url && change & Engine::Auto) { // We're not crossfading, and the pipeline is already playing the URI we // want, so just do nothing. @@ -419,7 +401,7 @@ bool GstEngine::Load(const QUrl& url, Engine::TrackChangeFlags change, } shared_ptr pipeline = - CreatePipeline(gst_url, force_stop_at_end ? end_nanosec : 0); + CreatePipeline(url, force_stop_at_end ? end_nanosec : 0); if (!pipeline) return false; if (crossfade) StartFadeout(); diff --git a/src/engines/gstengine.h b/src/engines/gstengine.h index 57ab8dfce..646f0ee6b 100644 --- a/src/engines/gstengine.h +++ b/src/engines/gstengine.h @@ -169,8 +169,6 @@ class GstEngine : public Engine::Base, public BufferConsumer { int AddBackgroundStream(std::shared_ptr pipeline); - static QUrl FixupUrl(const QUrl& url); - private: static const qint64 kTimerIntervalNanosec = 1000 * kNsecPerMsec; // 1s static const qint64 kPreloadGapNanosec = 2000 * kNsecPerMsec; // 2s diff --git a/src/engines/gstenginepipeline.cpp b/src/engines/gstenginepipeline.cpp index 0a4b0177e..8712d77c4 100644 --- a/src/engines/gstenginepipeline.cpp +++ b/src/engines/gstenginepipeline.cpp @@ -204,7 +204,7 @@ GstElement* GstEnginePipeline::CreateDecodeBinFromUrl(const QUrl& url) { str.remove(str.lastIndexOf(QChar('a')), 1); uri = str.toUtf8(); } else { - uri = url.toEncoded(); + uri = Utilities::GetUriForGstreamer(url); } new_bin = engine_->CreateElement("uridecodebin"); if (!new_bin) return nullptr; diff --git a/src/moodbar/moodbarpipeline.cpp b/src/moodbar/moodbarpipeline.cpp index 7d15f4d6d..ac62f3ef8 100644 --- a/src/moodbar/moodbarpipeline.cpp +++ b/src/moodbar/moodbarpipeline.cpp @@ -103,8 +103,8 @@ void MoodbarPipeline::Start() { builder_.reset(new MoodbarBuilder); // Set properties - g_object_set(decodebin, "uri", local_filename_.toEncoded().constData(), - nullptr); + QByteArray uri = Utilities::GetUriForGstreamer(local_filename_); + g_object_set(decodebin, "uri", uri.constData(), nullptr); g_object_set(spectrum, "bands", kBands, nullptr); GstFastSpectrum* fast_spectrum = GST_FASTSPECTRUM(spectrum);