summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS2
-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
5 files changed, 132 insertions, 2 deletions
diff --git a/NEWS b/NEWS
index 41e926619..00248d505 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,8 @@
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
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(