diff --git a/src/engines/gstengine.cpp b/src/engines/gstengine.cpp index ad0099434..918f59a67 100644 --- a/src/engines/gstengine.cpp +++ b/src/engines/gstengine.cpp @@ -85,7 +85,11 @@ using std::unique_ptr; using std::vector; const char* GstEngine::kSettingsGroup = "GstEngine"; +const char* GstEngine::kSettingFormat = "format"; const char* GstEngine::kAutoSink = "autoaudiosink"; +const char* GstEngine::kOutFormatDetect = ""; +const char* GstEngine::kOutFormatS16LE = "S16LE"; +const char* GstEngine::kOutFormatF32LE = "F32LE"; const char* GstEngine::kHypnotoadPipeline = "audiotestsrc wave=6 ! " "audioecho intensity=1 delay=50000000 ! " @@ -239,6 +243,8 @@ void GstEngine::ReloadSettings() { mono_playback_ = s.value("monoplayback", false).toBool(); sample_rate_ = s.value("samplerate", kAutoSampleRate).toInt(); + format_ = s.value(GstEngine::kSettingFormat, GstEngine::kOutFormatDetect) + .toString(); } qint64 GstEngine::position_nanosec() const { @@ -819,6 +825,7 @@ shared_ptr GstEngine::CreatePipeline() { ret->set_buffer_min_fill(buffer_min_fill_); ret->set_mono_playback(mono_playback_); ret->set_sample_rate(sample_rate_); + ret->set_format(format_); ret->AddBufferConsumer(this); for (BufferConsumer* consumer : buffer_consumers_) { diff --git a/src/engines/gstengine.h b/src/engines/gstengine.h index 92146c29c..2aa60f065 100644 --- a/src/engines/gstengine.h +++ b/src/engines/gstengine.h @@ -73,7 +73,11 @@ class GstEngine : public Engine::Base, public BufferConsumer { typedef QList OutputDetailsList; static const int kAutoSampleRate = -1; + static const char* kOutFormatDetect; + static const char* kOutFormatS16LE; + static const char* kOutFormatF32LE; static const char* kSettingsGroup; + static const char* kSettingFormat; static const char* kAutoSink; bool Init(); @@ -223,6 +227,7 @@ class GstEngine : public Engine::Base, public BufferConsumer { bool mono_playback_; int sample_rate_; + QString format_; mutable bool can_decode_success_; mutable bool can_decode_last_; diff --git a/src/engines/gstenginepipeline.cpp b/src/engines/gstenginepipeline.cpp index 97ef1aaa1..c5986f9b9 100644 --- a/src/engines/gstenginepipeline.cpp +++ b/src/engines/gstenginepipeline.cpp @@ -464,6 +464,11 @@ bool GstEnginePipeline::InitAudioBin() { // Link the trunk to the tee via filter. gst_element_link_many(tee_src, capsfilter_, tee_, nullptr); + // If the user has selected a format, then set it now. + if (format_ != GstEngine::kOutFormatDetect) { + SetOutputFormat(format_); + } + // Link the analyzer output of the tee gst_element_link(probe_queue, probe_converter); @@ -884,7 +889,9 @@ void GstEnginePipeline::NewPadCallback(GstElement*, GstPad* pad, qLog(Debug) << "Initial decoder caps:" << caps_str; g_free(caps_str); - if (instance->pipeline_is_initialised_) { + if (instance->format_ != GstEngine::kOutFormatDetect) { + // Caps were set when the pipeline was constructed. + } else if (instance->pipeline_is_initialised_) { qLog(Debug) << "Ignoring native format since pipeline is already running."; } else { @@ -892,11 +899,10 @@ void GstEnginePipeline::NewPadCallback(GstElement*, GstPad* pad, // The output branch only handles F32LE and S16LE. If the source is S16LE, // then use that throughout the pipeline. Otherwise, use F32LE. - if (fmt != "S16LE") { - GstCaps* new_caps = gst_caps_new_simple( - "audio/x-raw", "format", G_TYPE_STRING, "F32LE", nullptr); - g_object_set(instance->capsfilter_, "caps", new_caps, nullptr); - gst_caps_unref(new_caps); + if (fmt == GstEngine::kOutFormatS16LE) { + instance->SetOutputFormat(GstEngine::kOutFormatS16LE); + } else { + instance->SetOutputFormat(GstEngine::kOutFormatF32LE); } } gst_caps_unref(caps); @@ -1297,6 +1303,14 @@ void GstEnginePipeline::UpdateVolume() { g_object_set(G_OBJECT(volume_), "volume", vol, nullptr); } +void GstEnginePipeline::SetOutputFormat(const QString& format) { + qLog(Debug) << "Setting format to" << format; + GstCaps* new_caps = gst_caps_new_simple( + "audio/x-raw", "format", G_TYPE_STRING, format.toUtf8().data(), nullptr); + g_object_set(capsfilter_, "caps", new_caps, nullptr); + gst_caps_unref(new_caps); +} + void GstEnginePipeline::StartFader(qint64 duration_nanosec, QTimeLine::Direction direction, QTimeLine::CurveShape shape, diff --git a/src/engines/gstenginepipeline.h b/src/engines/gstenginepipeline.h index f6f231b11..e2e8cdbbc 100644 --- a/src/engines/gstenginepipeline.h +++ b/src/engines/gstenginepipeline.h @@ -51,6 +51,7 @@ class GstEnginePipeline : public GstPipelineBase { void set_buffer_min_fill(int percent); void set_mono_playback(bool enabled); void set_sample_rate(int rate); + void set_format(const QString& format) { format_ = format; } // Creates the pipeline, returns false on error bool InitFromReq(const MediaPlaybackRequest& req, qint64 end_nanosec); @@ -153,6 +154,7 @@ class GstEnginePipeline : public GstPipelineBase { void UpdateVolume(); void UpdateEqualizer(); void UpdateStereoBalance(); + void SetOutputFormat(const QString& format); bool ReplaceDecodeBin(GstElement* new_bin); bool ReplaceDecodeBin(const QUrl& url); @@ -215,6 +217,7 @@ class GstEnginePipeline : public GstPipelineBase { bool mono_playback_; int sample_rate_; + QString format_; // The URL that is currently playing, and the URL that is to be preloaded // when the current track is close to finishing. diff --git a/src/ui/playbacksettingspage.cpp b/src/ui/playbacksettingspage.cpp index e793378ac..b2fc1abb2 100644 --- a/src/ui/playbacksettingspage.cpp +++ b/src/ui/playbacksettingspage.cpp @@ -50,6 +50,10 @@ PlaybackSettingsPage::PlaybackSettingsPage(SettingsDialog* dialog) ui_->sample_rate->setItemData(2, 48000); ui_->sample_rate->setItemData(3, 96000); ui_->sample_rate->setItemData(4, 192000); + + ui_->output_format->setItemData(0, GstEngine::kOutFormatDetect); + ui_->output_format->setItemData(1, GstEngine::kOutFormatS16LE); + ui_->output_format->setItemData(2, GstEngine::kOutFormatF32LE); } PlaybackSettingsPage::~PlaybackSettingsPage() { delete ui_; } @@ -116,6 +120,9 @@ void PlaybackSettingsPage::Load() { ui_->mono_playback->setChecked(s.value("monoplayback", false).toBool()); ui_->sample_rate->setCurrentIndex(ui_->sample_rate->findData( s.value("samplerate", GstEngine::kAutoSampleRate).toInt())); + ui_->output_format->setCurrentIndex(ui_->output_format->findData( + s.value(GstEngine::kSettingFormat, GstEngine::kOutFormatDetect) + .toString())); ui_->buffer_min_fill->setValue(s.value("bufferminfill", 33).toInt()); s.endGroup(); } @@ -153,6 +160,9 @@ void PlaybackSettingsPage::Save() { s.setValue( "samplerate", ui_->sample_rate->itemData(ui_->sample_rate->currentIndex()).toInt()); + s.setValue(GstEngine::kSettingFormat, + ui_->output_format->itemData(ui_->output_format->currentIndex()) + .toString()); s.setValue("bufferminfill", ui_->buffer_min_fill->value()); s.endGroup(); } diff --git a/src/ui/playbacksettingspage.ui b/src/ui/playbacksettingspage.ui index f43a2cd55..ba56b17dd 100644 --- a/src/ui/playbacksettingspage.ui +++ b/src/ui/playbacksettingspage.ui @@ -7,7 +7,7 @@ 0 0 596 - 667 + 766 @@ -70,7 +70,16 @@ - + + 0 + + + 0 + + + 0 + + 0 @@ -193,7 +202,16 @@ false - + + 0 + + + 0 + + + 0 + + 0 @@ -336,16 +354,6 @@ - - - - Changing mono playback preference will be effective for the next playing songs - - - Mono playback - - - @@ -354,7 +362,7 @@ - + @@ -417,6 +425,65 @@ + + + + Format + + + + + + + Changing mono playback preference will be effective for the next playing songs + + + Mono playback + + + + + + + + + The format is only updated when a pipeline starts. + + + QComboBox::AdjustToContents + + + + Detect + + + + + S16LE (16-bit) + + + + + F32LE (32-bit) + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + +