summaryrefslogtreecommitdiff
path: root/src/filter
diff options
context:
space:
mode:
authorMax Kellermann <max@musicpd.org>2018-01-01 19:22:45 +0100
committerMax Kellermann <max@musicpd.org>2018-01-02 23:15:51 +0100
commit6d0d8cf9cf07a5d0905f715be9a79f5de86e8b37 (patch)
tree2fd9692a25b7e80ed67320a395bf0bbed1f9f91c /src/filter
parent14f669f4fbac72833e622f66f81950b4be3e3c12 (diff)
filter/Filter: add virtual method Flush()
This will be used by filters which have internal buffers which need to be flushed at the end, e.g. the "soxr" resampler.
Diffstat (limited to 'src/filter')
-rw-r--r--src/filter/Filter.cxx27
-rw-r--r--src/filter/Filter.hxx6
-rw-r--r--src/filter/Observer.cxx4
-rw-r--r--src/filter/plugins/ChainFilterPlugin.cxx49
4 files changed, 80 insertions, 6 deletions
diff --git a/src/filter/Filter.cxx b/src/filter/Filter.cxx
new file mode 100644
index 000000000..6a291cde9
--- /dev/null
+++ b/src/filter/Filter.cxx
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2003-2017 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 "Filter.hxx"
+#include "util/ConstBuffer.hxx"
+
+ConstBuffer<void>
+Filter::Flush()
+{
+ return nullptr;
+}
diff --git a/src/filter/Filter.hxx b/src/filter/Filter.hxx
index 6af002adc..7d714df79 100644
--- a/src/filter/Filter.hxx
+++ b/src/filter/Filter.hxx
@@ -62,6 +62,12 @@ public:
* or Reset() call)
*/
virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src) = 0;
+
+ /**
+ * Flush pending data and return it. This should be called
+ * repepatedly until it returns nullptr.
+ */
+ virtual ConstBuffer<void> Flush();
};
#endif
diff --git a/src/filter/Observer.cxx b/src/filter/Observer.cxx
index d51d6329e..a56efc70f 100644
--- a/src/filter/Observer.cxx
+++ b/src/filter/Observer.cxx
@@ -75,6 +75,10 @@ public:
ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override {
return filter->FilterPCM(src);
}
+
+ ConstBuffer<void> Flush() noexcept override {
+ return filter->Flush();
+ }
};
Filter *
diff --git a/src/filter/plugins/ChainFilterPlugin.cxx b/src/filter/plugins/ChainFilterPlugin.cxx
index 6fa273729..d95ae3768 100644
--- a/src/filter/plugins/ChainFilterPlugin.cxx
+++ b/src/filter/plugins/ChainFilterPlugin.cxx
@@ -43,6 +43,11 @@ class ChainFilter final : public Filter {
std::list<Child> children;
+ /**
+ * The child which will be flushed in the next Flush() call.
+ */
+ std::list<Child>::iterator flushing = children.end();
+
public:
explicit ChainFilter(AudioFormat _audio_format)
:Filter(_audio_format) {}
@@ -54,11 +59,20 @@ public:
assert(out_audio_format.IsValid());
children.emplace_back(name, std::move(filter));
+
+ RewindFlush();
}
/* virtual methods from class Filter */
void Reset() noexcept override;
ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override;
+ ConstBuffer<void> Flush() override;
+
+private:
+ void RewindFlush() {
+ flushing = children.begin();
+ }
+
};
class PreparedChainFilter final : public PreparedFilter {
@@ -118,23 +132,46 @@ PreparedChainFilter::Open(AudioFormat &in_audio_format)
void
ChainFilter::Reset() noexcept
{
+ RewindFlush();
+
for (auto &child : children)
child.filter->Reset();
}
-ConstBuffer<void>
-ChainFilter::FilterPCM(ConstBuffer<void> src)
+template<typename I>
+static ConstBuffer<void>
+ApplyFilterChain(I begin, I end, ConstBuffer<void> src)
{
- for (auto &child : children) {
+ for (auto i = begin; i != end; ++i)
/* feed the output of the previous filter as input
into the current one */
- src = child.filter->FilterPCM(src);
- }
+ src = i->filter->FilterPCM(src);
- /* return the output of the last filter */
return src;
}
+ConstBuffer<void>
+ChainFilter::FilterPCM(ConstBuffer<void> src)
+{
+ RewindFlush();
+
+ /* return the output of the last filter */
+ return ApplyFilterChain(children.begin(), children.end(), src);
+}
+
+ConstBuffer<void>
+ChainFilter::Flush()
+{
+ for (auto end = children.end(); flushing != end; ++flushing) {
+ auto data = flushing->filter->Flush();
+ if (!data.IsNull())
+ return ApplyFilterChain(std::next(flushing), end,
+ data);
+ }
+
+ return nullptr;
+}
+
std::unique_ptr<PreparedFilter>
filter_chain_new() noexcept
{