diff --git a/NEWS b/NEWS index 6a93361b1..421e70da9 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,7 @@ ver 0.22 (not yet released) * input - ffmpeg: allow partial reads * filter + - ffmpeg: new plugin based on FFmpeg's libavfilter library - hdcd: new plugin based on FFmpeg's "af_hdcd" for HDCD playback ver 0.21.7 (not yet released) diff --git a/doc/plugins.rst b/doc/plugins.rst index 340bbb5c0..238397558 100644 --- a/doc/plugins.rst +++ b/doc/plugins.rst @@ -1078,6 +1078,27 @@ The "Solaris" plugin runs only on SUN Solaris, and plays via /dev/audio. Filter plugins -------------- +ffmpeg +~~~~~~ + +Decode `HDCD +`_. + +This plugin requires building with ``libavfilter`` (FFmpeg). + +.. list-table:: + :widths: 20 80 + :header-rows: 1 + + * - Setting + - Description + * - **graph "..."** + - Specifies the ``libavfilter`` graph; read the `FFmpeg + documentation + `_ + for details + + hdcd ~~~~ diff --git a/src/filter/FilterRegistry.cxx b/src/filter/FilterRegistry.cxx index a9995c4ee..3cd421a81 100644 --- a/src/filter/FilterRegistry.cxx +++ b/src/filter/FilterRegistry.cxx @@ -22,6 +22,7 @@ #include "plugins/NullFilterPlugin.hxx" #include "plugins/RouteFilterPlugin.hxx" #include "plugins/NormalizeFilterPlugin.hxx" +#include "plugins/FfmpegFilterPlugin.hxx" #include "plugins/HdcdFilterPlugin.hxx" #include "config.h" @@ -32,6 +33,7 @@ static const FilterPlugin *const filter_plugins[] = { &route_filter_plugin, &normalize_filter_plugin, #ifdef HAVE_LIBAVFILTER + &ffmpeg_filter_plugin, &hdcd_filter_plugin, #endif nullptr, diff --git a/src/filter/plugins/FfmpegFilterPlugin.cxx b/src/filter/plugins/FfmpegFilterPlugin.cxx new file mode 100644 index 000000000..6efca1398 --- /dev/null +++ b/src/filter/plugins/FfmpegFilterPlugin.cxx @@ -0,0 +1,91 @@ +/* + * Copyright 2003-2019 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 "FfmpegFilterPlugin.hxx" +#include "FfmpegFilter.hxx" +#include "filter/FilterPlugin.hxx" +#include "filter/Filter.hxx" +#include "filter/Prepared.hxx" +#include "filter/FilterRegistry.hxx" +#include "lib/ffmpeg/Filter.hxx" +#include "config/Block.hxx" +#include "AudioFormat.hxx" + +class PreparedFfmpegFilter final : public PreparedFilter { + const char *const graph_string; + +public: + explicit PreparedFfmpegFilter(const char *_graph) noexcept + :graph_string(_graph) {} + + /* virtual methods from class PreparedFilter */ + std::unique_ptr Open(AudioFormat &af) override; +}; + +std::unique_ptr +PreparedFfmpegFilter::Open(AudioFormat &in_audio_format) +{ + Ffmpeg::FilterGraph graph; + + auto buffer_src = + Ffmpeg::FilterContext::MakeAudioBufferSource(in_audio_format, + *graph); + + auto buffer_sink = Ffmpeg::FilterContext::MakeAudioBufferSink(*graph); + + Ffmpeg::FilterInOut io_sink("out", *buffer_sink); + Ffmpeg::FilterInOut io_src("in", *buffer_src); + auto io = graph.Parse(graph_string, std::move(io_sink), + std::move(io_src)); + + if (io.first.get() != nullptr) + throw std::runtime_error("FFmpeg filter has an open input"); + + if (io.second.get() != nullptr) + throw std::runtime_error("FFmpeg filter has an open output"); + + graph.CheckAndConfigure(); + + auto out_audio_format = in_audio_format; // TODO + + return std::make_unique(in_audio_format, + out_audio_format, + std::move(graph), + std::move(buffer_src), + std::move(buffer_sink)); +} + +static std::unique_ptr +ffmpeg_filter_init(const ConfigBlock &block) +{ + const char *graph = block.GetBlockValue("graph"); + if (graph == nullptr) + throw std::runtime_error("Missing \"graph\" configuration"); + + /* check if the graph can be parsed (and discard the + object) */ + Ffmpeg::FilterGraph().Parse(graph); + + return std::make_unique(graph); +} + +const FilterPlugin ffmpeg_filter_plugin = { + "ffmpeg", + ffmpeg_filter_init, +}; diff --git a/src/filter/plugins/FfmpegFilterPlugin.hxx b/src/filter/plugins/FfmpegFilterPlugin.hxx new file mode 100644 index 000000000..92c048820 --- /dev/null +++ b/src/filter/plugins/FfmpegFilterPlugin.hxx @@ -0,0 +1,27 @@ +/* + * Copyright 2003-2019 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_FILTER_PLUGIN_HXX +#define MPD_FFMPEG_FILTER_PLUGIN_HXX + +struct FilterPlugin; + +extern const FilterPlugin ffmpeg_filter_plugin; + +#endif diff --git a/src/filter/plugins/meson.build b/src/filter/plugins/meson.build index b9130a090..e25193092 100644 --- a/src/filter/plugins/meson.build +++ b/src/filter/plugins/meson.build @@ -4,6 +4,7 @@ filter_plugins_deps = [] if libavfilter_dep.found() filter_plugins_sources += [ 'FfmpegFilter.cxx', + 'FfmpegFilterPlugin.cxx', 'HdcdFilterPlugin.cxx', ] filter_plugins_deps += ffmpeg_dep