summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Kellermann <max@musicpd.org>2020-11-16 09:41:20 +0100
committerMax Kellermann <max@musicpd.org>2020-11-16 09:41:20 +0100
commitfbbbfb9668f1411a2af0c2928a16c4f13e5f76b1 (patch)
treea7e4cad7b2c0c9fc59566b1ccbb768f44e8505f5
parenteb9f5339b683d037ab3224e362071e22991e0e83 (diff)
parent38b41fc3fdc11300296809c08313eca0d6698f76 (diff)
Merge branch 'v0.22.x'
-rw-r--r--NEWS4
-rw-r--r--src/command/PartitionCommands.cxx5
-rw-r--r--src/filter/plugins/FfmpegFilterPlugin.cxx5
-rw-r--r--src/lib/ffmpeg/DetectFilterFormat.cxx76
-rw-r--r--src/lib/ffmpeg/DetectFilterFormat.hxx46
-rw-r--r--src/lib/ffmpeg/meson.build5
-rw-r--r--src/output/Control.cxx11
-rw-r--r--src/output/Control.hxx3
-rw-r--r--src/output/MultipleOutputs.cxx13
-rw-r--r--src/output/MultipleOutputs.hxx4
10 files changed, 167 insertions, 5 deletions
diff --git a/NEWS b/NEWS
index 697cad074..03110dc7b 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,10 @@ ver 0.23 (not yet released)
ver 0.22.4 (not yet released)
* decoder
- dsdiff: apply padding to odd-sized chunks
+* filter
+ - ffmpeg: detect the output sample format
+* output
+ - moveoutput: fix always_on and tag lost on move
ver 0.22.3 (2020/11/06)
* playlist
diff --git a/src/command/PartitionCommands.cxx b/src/command/PartitionCommands.cxx
index fbcb8a754..9d260425f 100644
--- a/src/command/PartitionCommands.cxx
+++ b/src/command/PartitionCommands.cxx
@@ -183,9 +183,8 @@ handle_moveoutput(Client &client, Request request, Response &response)
existing_output->ReplaceDummy(output->Steal(),
was_enabled);
else
- /* add it to the output list */
- dest_partition.outputs.Add(output->Steal(),
- was_enabled);
+ /* copy the AudioOutputControl and add it to the output list */
+ dest_partition.outputs.AddCopy(output,was_enabled);
instance.EmitIdle(IDLE_OUTPUT);
return CommandResult::OK;
diff --git a/src/filter/plugins/FfmpegFilterPlugin.cxx b/src/filter/plugins/FfmpegFilterPlugin.cxx
index 168ff52bf..fcb255be0 100644
--- a/src/filter/plugins/FfmpegFilterPlugin.cxx
+++ b/src/filter/plugins/FfmpegFilterPlugin.cxx
@@ -23,6 +23,7 @@
#include "filter/Filter.hxx"
#include "filter/Prepared.hxx"
#include "lib/ffmpeg/Filter.hxx"
+#include "lib/ffmpeg/DetectFilterFormat.hxx"
#include "config/Block.hxx"
class PreparedFfmpegFilter final : public PreparedFilter {
@@ -60,7 +61,9 @@ PreparedFfmpegFilter::Open(AudioFormat &in_audio_format)
graph.CheckAndConfigure();
- auto out_audio_format = in_audio_format; // TODO
+ const auto out_audio_format =
+ Ffmpeg::DetectFilterOutputFormat(in_audio_format, *buffer_src,
+ *buffer_sink);
return std::make_unique<FfmpegFilter>(in_audio_format,
out_audio_format,
diff --git a/src/lib/ffmpeg/DetectFilterFormat.cxx b/src/lib/ffmpeg/DetectFilterFormat.cxx
new file mode 100644
index 000000000..65b610024
--- /dev/null
+++ b/src/lib/ffmpeg/DetectFilterFormat.cxx
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2003-2020 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "DetectFilterFormat.hxx"
+#include "Frame.hxx"
+#include "SampleFormat.hxx"
+#include "pcm/Silence.hxx"
+#include "pcm/CheckAudioFormat.hxx"
+#include "util/WritableBuffer.hxx"
+
+extern "C" {
+#include <libavfilter/buffersrc.h>
+#include <libavfilter/buffersink.h>
+}
+
+#include <cassert>
+
+namespace Ffmpeg {
+
+AudioFormat
+DetectFilterOutputFormat(const AudioFormat &in_audio_format,
+ AVFilterContext &buffer_src,
+ AVFilterContext &buffer_sink)
+{
+ uint_least64_t silence[MAX_CHANNELS];
+ const size_t silence_size = in_audio_format.GetFrameSize();
+ assert(sizeof(silence) >= silence_size);
+
+ PcmSilence(WritableBuffer<void>{&silence, silence_size},
+ in_audio_format.format);
+
+ Frame frame;
+ frame->format = ToFfmpegSampleFormat(in_audio_format.format);
+ frame->sample_rate = in_audio_format.sample_rate;
+ frame->channels = in_audio_format.channels;
+ frame->nb_samples = 1;
+
+ frame.GetBuffer();
+
+ memcpy(frame.GetData(0), silence, silence_size);
+
+ int err = av_buffersrc_add_frame(&buffer_src, frame.get());
+ if (err < 0)
+ throw MakeFfmpegError(err, "av_buffersrc_add_frame() failed");
+
+ frame.Unref();
+
+ err = av_buffersink_get_frame(&buffer_sink, frame.get());
+ if (err < 0)
+ throw MakeFfmpegError(err, "av_buffersink_get_frame() failed");
+
+ const SampleFormat sample_format = FromFfmpegSampleFormat(AVSampleFormat(frame->format));
+ if (sample_format == SampleFormat::UNDEFINED)
+ throw std::runtime_error("Unsupported FFmpeg sample format");
+
+ return CheckAudioFormat(frame->sample_rate, sample_format,
+ frame->channels);
+}
+
+} // namespace Ffmpeg
diff --git a/src/lib/ffmpeg/DetectFilterFormat.hxx b/src/lib/ffmpeg/DetectFilterFormat.hxx
new file mode 100644
index 000000000..6e9e3877c
--- /dev/null
+++ b/src/lib/ffmpeg/DetectFilterFormat.hxx
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2003-2020 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_FFMPEG_DETECT_FILTER_FORMAT_HXX
+#define MPD_FFMPEG_DETECT_FILTER_FORMAT_HXX
+
+struct AVFilterContext;
+struct AudioFormat;
+
+namespace Ffmpeg {
+
+/**
+ * Attempt to detect the output format of the given FFmpeg filter by
+ * sending one frame of silence and checking what format comes back
+ * from the filter.
+ *
+ * This is a kludge because MPD needs to know the output format of a
+ * filter while initializing and cannot cope with format changes in
+ * between.
+ *
+ * This function can throw if the FFmpeg filter fails.
+ */
+AudioFormat
+DetectFilterOutputFormat(const AudioFormat &in_audio_format,
+ AVFilterContext &buffer_src,
+ AVFilterContext &buffer_sink);
+
+} // namespace Ffmpeg
+
+#endif
diff --git a/src/lib/ffmpeg/meson.build b/src/lib/ffmpeg/meson.build
index fde110edc..31eda8167 100644
--- a/src/lib/ffmpeg/meson.build
+++ b/src/lib/ffmpeg/meson.build
@@ -20,7 +20,10 @@ endif
ffmpeg_sources = []
if libavfilter_dep.found()
- ffmpeg_sources += 'Filter.cxx'
+ ffmpeg_sources += [
+ 'Filter.cxx',
+ 'DetectFilterFormat.cxx',
+ ]
endif
ffmpeg = static_library(
diff --git a/src/output/Control.cxx b/src/output/Control.cxx
index fd4a1aa50..035739312 100644
--- a/src/output/Control.cxx
+++ b/src/output/Control.cxx
@@ -39,6 +39,17 @@ AudioOutputControl::AudioOutputControl(std::unique_ptr<FilteredAudioOutput> _out
{
}
+AudioOutputControl::AudioOutputControl(AudioOutputControl *_output,
+ AudioOutputClient &_client) noexcept
+ :output(_output->Steal()),
+ name(output->GetName()),
+ client(_client),
+ thread(BIND_THIS_METHOD(Task))
+{
+ tags =_output->tags;
+ always_on=_output->always_on;
+}
+
AudioOutputControl::~AudioOutputControl() noexcept
{
StopThread();
diff --git a/src/output/Control.hxx b/src/output/Control.hxx
index 809c65101..ab8637f47 100644
--- a/src/output/Control.hxx
+++ b/src/output/Control.hxx
@@ -245,6 +245,9 @@ public:
AudioOutputControl(std::unique_ptr<FilteredAudioOutput> _output,
AudioOutputClient &_client) noexcept;
+ AudioOutputControl(AudioOutputControl *_outputControl,
+ AudioOutputClient &_client) noexcept;
+
~AudioOutputControl() noexcept;
AudioOutputControl(const AudioOutputControl &) = delete;
diff --git a/src/output/MultipleOutputs.cxx b/src/output/MultipleOutputs.cxx
index 71014e8d1..0639d51c7 100644
--- a/src/output/MultipleOutputs.cxx
+++ b/src/output/MultipleOutputs.cxx
@@ -141,6 +141,19 @@ MultipleOutputs::Add(std::unique_ptr<FilteredAudioOutput> output,
}
void
+MultipleOutputs::AddCopy(AudioOutputControl *outputControl,
+ bool enable) noexcept
+{
+ // TODO: this operation needs to be protected with a mutex
+ outputs.emplace_back(std::make_unique<AudioOutputControl>(outputControl,
+ client));
+
+ outputs.back()->LockSetEnabled(enable);
+
+ client.ApplyEnabled();
+}
+
+void
MultipleOutputs::EnableDisable()
{
/* parallel execution */
diff --git a/src/output/MultipleOutputs.hxx b/src/output/MultipleOutputs.hxx
index 9c885cb3a..6b3e538c2 100644
--- a/src/output/MultipleOutputs.hxx
+++ b/src/output/MultipleOutputs.hxx
@@ -128,6 +128,10 @@ public:
void Add(std::unique_ptr<FilteredAudioOutput> output,
bool enable) noexcept;
+ void AddCopy(AudioOutputControl *outputControl,
+ bool enable) noexcept;
+
+
void SetReplayGainMode(ReplayGainMode mode) noexcept;
/**