From 077d715da0a819f9320f8109c85ce7366d525024 Mon Sep 17 00:00:00 2001 From: Jay Moore Date: Thu, 30 Oct 2025 13:02:39 -0400 Subject: [PATCH] Another 1.0 candidate before I start stripping meson options --- meson.build | 7 +- meson_options.txt | 55 +-- src/encoder/Configured.cxx | 40 -- src/encoder/Configured.hxx | 22 +- src/encoder/EncoderAPI.hxx | 22 - src/encoder/EncoderInterface.hxx | 116 +---- src/encoder/EncoderList.cxx | 55 --- src/encoder/EncoderList.hxx | 46 +- src/encoder/EncoderPlugin.hxx | 23 +- src/encoder/Features.h | 11 + src/encoder/ToOutputStream.cxx | 23 - src/encoder/ToOutputStream.hxx | 16 - src/encoder/meson.build | 50 --- src/encoder/plugins/FlacEncoderPlugin.cxx | 288 ------------- src/encoder/plugins/FlacEncoderPlugin.hxx | 9 - src/encoder/plugins/LameEncoderPlugin.cxx | 187 -------- src/encoder/plugins/LameEncoderPlugin.hxx | 9 - src/encoder/plugins/NullEncoderPlugin.cxx | 42 -- src/encoder/plugins/NullEncoderPlugin.hxx | 9 - src/encoder/plugins/OggEncoder.hxx | 55 --- src/encoder/plugins/OpusEncoderPlugin.cxx | 402 ------------------ src/encoder/plugins/OpusEncoderPlugin.hxx | 9 - src/encoder/plugins/ShineEncoderPlugin.cxx | 193 --------- src/encoder/plugins/ShineEncoderPlugin.hxx | 9 - src/encoder/plugins/TwolameEncoderPlugin.cxx | 209 --------- src/encoder/plugins/TwolameEncoderPlugin.hxx | 9 - src/encoder/plugins/VorbisEncoderPlugin.cxx | 251 ----------- src/encoder/plugins/VorbisEncoderPlugin.hxx | 9 - src/encoder/plugins/WaveEncoderPlugin.cxx | 213 +--------- src/encoder/plugins/WaveEncoderPlugin.hxx | 12 +- src/encoder/plugins/meson.build | 80 ---- src/filter/Factory.cxx | 23 - src/filter/Factory.hxx | 14 +- src/filter/Filter.cxx | 14 + src/filter/Filter.hxx | 82 +--- src/filter/FilterPlugin.hxx | 27 -- src/filter/LoadChain.cxx | 40 -- src/filter/LoadChain.hxx | 31 +- src/filter/LoadOne.cxx | 24 -- src/filter/LoadOne.hxx | 23 - src/filter/NullFilter.hxx | 18 - src/filter/Observer.cxx | 114 ----- src/filter/Observer.hxx | 25 +- src/filter/Prepared.hxx | 23 +- src/filter/Registry.cxx | 34 -- src/filter/Registry.hxx | 19 - src/filter/meson.build | 24 +- .../plugins/AutoConvertFilterPlugin.cxx | 56 --- .../plugins/AutoConvertFilterPlugin.hxx | 20 +- src/filter/plugins/ConvertFilterPlugin.cxx | 118 ----- src/filter/plugins/ConvertFilterPlugin.hxx | 40 +- src/filter/plugins/FfmpegFilter.cxx | 104 ----- src/filter/plugins/FfmpegFilter.hxx | 62 --- src/filter/plugins/FfmpegFilterPlugin.cxx | 114 ----- src/filter/plugins/FfmpegFilterPlugin.hxx | 11 - src/filter/plugins/HdcdFilterPlugin.cxx | 79 ---- src/filter/plugins/HdcdFilterPlugin.hxx | 11 - src/filter/plugins/NormalizeFilterPlugin.cxx | 73 ---- src/filter/plugins/NormalizeFilterPlugin.hxx | 17 +- src/filter/plugins/NullFilterPlugin.cxx | 32 -- src/filter/plugins/NullFilterPlugin.hxx | 11 - src/filter/plugins/ReplayGainFilterPlugin.cxx | 217 ---------- src/filter/plugins/ReplayGainFilterPlugin.hxx | 68 ++- src/filter/plugins/RouteFilterPlugin.cxx | 260 ----------- src/filter/plugins/RouteFilterPlugin.hxx | 11 - src/filter/plugins/TwoFilters.cxx | 100 ----- src/filter/plugins/TwoFilters.hxx | 71 +--- src/filter/plugins/VolumeFilterPlugin.cxx | 71 ---- src/filter/plugins/VolumeFilterPlugin.hxx | 23 +- src/filter/plugins/meson.build | 38 -- src/output/meson.build | 4 +- test/meson.build | 63 +-- 72 files changed, 312 insertions(+), 4378 deletions(-) delete mode 100644 src/encoder/Configured.cxx delete mode 100644 src/encoder/EncoderAPI.hxx delete mode 100644 src/encoder/EncoderList.cxx create mode 100644 src/encoder/Features.h delete mode 100644 src/encoder/ToOutputStream.cxx delete mode 100644 src/encoder/ToOutputStream.hxx delete mode 100644 src/encoder/meson.build delete mode 100644 src/encoder/plugins/FlacEncoderPlugin.cxx delete mode 100644 src/encoder/plugins/FlacEncoderPlugin.hxx delete mode 100644 src/encoder/plugins/LameEncoderPlugin.cxx delete mode 100644 src/encoder/plugins/LameEncoderPlugin.hxx delete mode 100644 src/encoder/plugins/NullEncoderPlugin.cxx delete mode 100644 src/encoder/plugins/NullEncoderPlugin.hxx delete mode 100644 src/encoder/plugins/OggEncoder.hxx delete mode 100644 src/encoder/plugins/OpusEncoderPlugin.cxx delete mode 100644 src/encoder/plugins/OpusEncoderPlugin.hxx delete mode 100644 src/encoder/plugins/ShineEncoderPlugin.cxx delete mode 100644 src/encoder/plugins/ShineEncoderPlugin.hxx delete mode 100644 src/encoder/plugins/TwolameEncoderPlugin.cxx delete mode 100644 src/encoder/plugins/TwolameEncoderPlugin.hxx delete mode 100644 src/encoder/plugins/VorbisEncoderPlugin.cxx delete mode 100644 src/encoder/plugins/VorbisEncoderPlugin.hxx delete mode 100644 src/encoder/plugins/meson.build delete mode 100644 src/filter/Factory.cxx create mode 100644 src/filter/Filter.cxx delete mode 100644 src/filter/FilterPlugin.hxx delete mode 100644 src/filter/LoadChain.cxx delete mode 100644 src/filter/LoadOne.cxx delete mode 100644 src/filter/LoadOne.hxx delete mode 100644 src/filter/NullFilter.hxx delete mode 100644 src/filter/Observer.cxx delete mode 100644 src/filter/Registry.cxx delete mode 100644 src/filter/Registry.hxx delete mode 100644 src/filter/plugins/AutoConvertFilterPlugin.cxx delete mode 100644 src/filter/plugins/ConvertFilterPlugin.cxx delete mode 100644 src/filter/plugins/FfmpegFilter.cxx delete mode 100644 src/filter/plugins/FfmpegFilter.hxx delete mode 100644 src/filter/plugins/FfmpegFilterPlugin.cxx delete mode 100644 src/filter/plugins/FfmpegFilterPlugin.hxx delete mode 100644 src/filter/plugins/HdcdFilterPlugin.cxx delete mode 100644 src/filter/plugins/HdcdFilterPlugin.hxx delete mode 100644 src/filter/plugins/NormalizeFilterPlugin.cxx delete mode 100644 src/filter/plugins/NullFilterPlugin.cxx delete mode 100644 src/filter/plugins/NullFilterPlugin.hxx delete mode 100644 src/filter/plugins/ReplayGainFilterPlugin.cxx delete mode 100644 src/filter/plugins/RouteFilterPlugin.cxx delete mode 100644 src/filter/plugins/RouteFilterPlugin.hxx delete mode 100644 src/filter/plugins/TwoFilters.cxx delete mode 100644 src/filter/plugins/VolumeFilterPlugin.cxx delete mode 100644 src/filter/plugins/meson.build diff --git a/meson.build b/meson.build index 9bb6545..dc74b86 100644 --- a/meson.build +++ b/meson.build @@ -469,12 +469,13 @@ subdir('src/tag') subdir('src/neighbor') subdir('src/input') subdir('src/archive') -subdir('src/filter') +subdir('src/filter') # Stub implementations for compatibility subdir('src/mixer') subdir('src/output') subdir('src/lib/xiph') subdir('src/decoder') -subdir('src/encoder') +# subdir('src/encoder') # Removed - not needed for database creation +encoder_glue_dep = declare_dependency() # Empty dependency for compatibility subdir('src/song') subdir('src/playlist') @@ -605,7 +606,7 @@ mpd_dbcreate = executable( sqlite_dep, neighbor_glue_dep, output_glue_dep, - encoder_glue_dep, + # encoder_glue_dep, # Removed - not needed for database creation mixer_glue_dep, more_deps, fmt_dep, diff --git a/meson_options.txt b/meson_options.txt index f25f2a2..3a5af1a 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -4,7 +4,7 @@ option('manpages', type: 'boolean', value: false, description: 'Build manual pag option('doxygen', type: 'boolean', value: false, description: 'Build doxygen source documentation') option('syslog', type: 'feature', description: 'syslog support') -option('inotify', type: 'boolean', value: true, description: 'inotify support (for automatic database update)') +option('inotify', type: 'boolean', value: false, description: 'inotify support (for automatic database update)') option('io_uring', type: 'feature', description: 'Linux io_uring support using liburing') # Daemon and systemd options removed - mpd-dbcreate is a standalone utility, not a daemon @@ -38,23 +38,13 @@ option('dsd', type: 'boolean', value: true, description: 'Support the DSD audio # option('database', type: 'boolean', value: true, description: 'enable support for the music database') -option('upnp', type: 'combo', - choices: ['auto', 'pupnp', 'npupnp', 'disabled'], - value: 'auto', - description: 'UPnP client support') - -# -# Neighbor plugins -# - -option('neighbor', type: 'boolean', value: true, description: 'enable support for neighbor discovery') # # Storage plugins # option('udisks', type: 'feature', description: 'Support for removable media using udisks2') -option('webdav', type: 'feature', description: 'WebDAV support using CURL and Expat') + # # Playlist plugins @@ -76,11 +66,6 @@ option('nfs', type: 'feature', description: 'NFS protocol support using libnfs') # https://bugzilla.samba.org/show_bug.cgi?id=11413 option('smbclient', type: 'feature', value: 'disabled', description: 'SMB support using libsmbclient') -# -# Commercial services -# - -option('qobuz', type: 'feature', description: 'Qobuz client') # # Archive plugins @@ -122,42 +107,6 @@ option('vorbis', type: 'feature', description: 'Vorbis decoder plugin') option('wavpack', type: 'feature', description: 'WavPack decoder plugin') option('wildmidi', type: 'feature', description: 'WildMidi decoder plugin') -# -# Encoder plugins -# - -option('vorbisenc', type: 'feature', description: 'Vorbis encoder plugin') -option('lame', type: 'feature', description: 'LAME MP3 encoder plugin') -option('twolame', type: 'feature', description: 'TwoLAME MP2 encoder plugin') -option('shine', type: 'feature', description: 'shine MP3 encoder plugin') -option('wave_encoder', type: 'boolean', value: true, description: 'PCM wave encoder encoder plugin') - -# -# Filter plugins -# - -option('libsamplerate', type: 'feature', value: 'disabled', description: 'libsamplerate resampler') -option('soxr', type: 'feature', value: 'disabled', description: 'libsoxr resampler') - -# -# Output plugins -# - -option('alsa', type: 'feature', value: 'disabled', description: 'ALSA support') -option('ao', type: 'feature', value: 'disabled', description: 'libao output plugin') -option('fifo', type: 'boolean', value: false, description: 'FIFO output plugin') -option('httpd', type: 'boolean', value: false, description: 'HTTP streaming output plugin') -option('jack', type: 'feature', value: 'disabled', description: 'JACK output plugin') -option('openal', type: 'feature', value: 'disabled', description: 'OpenAL output plugin') -option('oss', type: 'feature', value: 'disabled', description: 'Open Sound System support') -option('pipe', type: 'boolean', value: false, description: 'Pipe output plugin') -option('pipewire', type: 'feature', value: 'disabled', description: 'PipeWire support') -option('pulse', type: 'feature', value: 'disabled', description: 'PulseAudio support') -option('recorder', type: 'boolean', value: false, description: 'Recorder output plugin') -option('shout', type: 'feature', value: 'disabled', description: 'Shoutcast streaming support using libshout') -option('snapcast', type: 'boolean', value: false, description: 'Snapcast output plugin') -option('sndio', type: 'feature', value: 'disabled', description: 'sndio output plugin') -option('solaris_output', type: 'feature', value: 'disabled', description: 'Solaris /dev/audio support') # # Misc libraries diff --git a/src/encoder/Configured.cxx b/src/encoder/Configured.cxx deleted file mode 100644 index 49f35b7..0000000 --- a/src/encoder/Configured.cxx +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#include "Configured.hxx" -#include "EncoderList.hxx" -#include "EncoderPlugin.hxx" -#include "config/Block.hxx" -#include "lib/fmt/RuntimeError.hxx" -#include "util/StringAPI.hxx" - -static const EncoderPlugin & -GetConfiguredEncoderPlugin(const ConfigBlock &block, bool shout_legacy) -{ - const char *name = block.GetBlockValue("encoder", nullptr); - if (name == nullptr && shout_legacy) - name = block.GetBlockValue("encoding", nullptr); - - if (name == nullptr) - name = "vorbis"; - - if (shout_legacy) { - if (StringIsEqual(name, "ogg")) - name = "vorbis"; - else if (StringIsEqual(name, "mp3")) - name = "lame"; - } - - const auto plugin = encoder_plugin_get(name); - if (plugin == nullptr) - throw FmtRuntimeError("No such encoder: {}", name); - - return *plugin; -} - -PreparedEncoder * -CreateConfiguredEncoder(const ConfigBlock &block, bool shout_legacy) -{ - return encoder_init(GetConfiguredEncoderPlugin(block, shout_legacy), - block); -} diff --git a/src/encoder/Configured.hxx b/src/encoder/Configured.hxx index 5c675ea..1d8920c 100644 --- a/src/encoder/Configured.hxx +++ b/src/encoder/Configured.hxx @@ -1,23 +1,23 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Copyright The Music Player Daemon Project +// STUB FILE - Encoder support removed for mpd-dbcreate #ifndef MPD_ENCODER_CONFIGURED_HXX #define MPD_ENCODER_CONFIGURED_HXX +#include "EncoderInterface.hxx" + struct ConfigBlock; -class PreparedEncoder; +class AudioFormat; /** - * Create a #PreparedEncoder instance from the settings in the - * #ConfigBlock. Its "encoder" setting is used to choose the encoder - * plugin. - * - * Throws an exception on error. - * - * @param shout_legacy enable the "shout" plugin legacy configuration? - * i.e. fall back to setting "encoding" instead of "encoder" + * Stub implementation - encoder support not needed for database creation */ -PreparedEncoder * -CreateConfiguredEncoder(const ConfigBlock &block, bool shout_legacy=false); +inline EncoderPtr +encoder_init([[maybe_unused]] const ConfigBlock &block, + [[maybe_unused]] AudioFormat &audio_format) +{ + return nullptr; +} #endif diff --git a/src/encoder/EncoderAPI.hxx b/src/encoder/EncoderAPI.hxx deleted file mode 100644 index 0f75bce..0000000 --- a/src/encoder/EncoderAPI.hxx +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -/* - * This header is included by encoder plugins. - * - */ - -#ifndef MPD_ENCODER_API_HXX -#define MPD_ENCODER_API_HXX - -// IWYU pragma: begin_exports - -#include "EncoderInterface.hxx" -#include "EncoderPlugin.hxx" -#include "pcm/AudioFormat.hxx" -#include "tag/Tag.hxx" -#include "config/Block.hxx" - -// IWYU pragma: end_exports - -#endif diff --git a/src/encoder/EncoderInterface.hxx b/src/encoder/EncoderInterface.hxx index 6cdd163..3c802d9 100644 --- a/src/encoder/EncoderInterface.hxx +++ b/src/encoder/EncoderInterface.hxx @@ -1,122 +1,20 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Copyright The Music Player Daemon Project +// STUB FILE - Encoder support removed for mpd-dbcreate #ifndef MPD_ENCODER_INTERFACE_HXX #define MPD_ENCODER_INTERFACE_HXX -#include -#include - -struct AudioFormat; -struct Tag; +#include +/** + * Stub implementation - encoder support not needed for database creation + */ class Encoder { - const bool implements_tag; - public: - explicit Encoder(bool _implements_tag) noexcept - :implements_tag(_implements_tag) {} - virtual ~Encoder() noexcept = default; - - bool ImplementsTag() const noexcept { - return implements_tag; - } - - /** - * Ends the stream: flushes the encoder object, generate an - * end-of-stream marker (if applicable), make everything which - * might currently be buffered available by Read(). - * - * After this function has been called, the encoder may not be - * usable for more data, and only Read() can be called. - * - * Throws on error. - */ - virtual void End() { - } - - /** - * Flushes an encoder object, make everything which might - * currently be buffered available by Read(). - * - * Throws on error. - */ - virtual void Flush() { - } - - /** - * Prepare for sending a tag to the encoder. This is used by - * some encoders to flush the previous sub-stream, in - * preparation to begin a new one. - * - * Throws on error. - */ - virtual void PreTag() { - } - - /** - * Sends a tag to the encoder. - * - * Instructions: call PreTag(); then obtain flushed data with - * Read(); finally call Tag() and again Read(). - * - * Throws on error. - * - * @param tag the tag object - */ - virtual void SendTag([[maybe_unused]] const Tag &tag) { - } - - /** - * Writes raw PCM data to the encoder. - * - * Throws on error. - * - * @param data the buffer containing PCM samples - * @param length the length of the buffer in bytes - */ - virtual void Write(std::span src) = 0; - - /** - * Reads encoded data from the encoder. - * - * Call this repeatedly after End(), Flush(), PreTag(), SendTag() and - * Write() until no more data is returned. - * - * @param buffer a buffer that can be used to write data into - * - * @return the portion of the buffer that was filled (but may - * also point to a different buffer, e.g. one owned by this object) - */ - virtual std::span Read(std::span buffer) noexcept = 0; + virtual ~Encoder() = default; }; -class PreparedEncoder { -public: - virtual ~PreparedEncoder() noexcept = default; - - /** - * Create an #Encoder instance. - * - * After this function returns successfully and before the - * first Encoder::Write() call, you should invoke - * Encoder::Read() to obtain the file header. - * - * Throws on error. - * - * @param audio_format the encoder's input audio format; the plugin - * may modify the struct to adapt it to its abilities - */ - virtual Encoder *Open(AudioFormat &audio_format) = 0; - - /** - * Get mime type of encoded content. - * - * @return an constant string, nullptr on failure - */ - virtual const char *GetMimeType() const noexcept { - return nullptr; - } -}; +using EncoderPtr = std::unique_ptr; #endif diff --git a/src/encoder/EncoderList.cxx b/src/encoder/EncoderList.cxx deleted file mode 100644 index 39083f4..0000000 --- a/src/encoder/EncoderList.cxx +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#include "config.h" -#include "EncoderList.hxx" -#include "EncoderPlugin.hxx" -#include "encoder/Features.h" -#include "plugins/NullEncoderPlugin.hxx" -#include "plugins/WaveEncoderPlugin.hxx" -#include "plugins/VorbisEncoderPlugin.hxx" -#include "plugins/OpusEncoderPlugin.hxx" -#include "plugins/FlacEncoderPlugin.hxx" -#include "plugins/ShineEncoderPlugin.hxx" -#include "plugins/LameEncoderPlugin.hxx" -#include "plugins/TwolameEncoderPlugin.hxx" -#include "decoder/Features.h" - -#include - -constinit const EncoderPlugin *const encoder_plugins[] = { - &null_encoder_plugin, -#ifdef ENABLE_VORBISENC - &vorbis_encoder_plugin, -#endif -#ifdef ENABLE_OPUS - &opus_encoder_plugin, -#endif -#ifdef ENABLE_LAME - &lame_encoder_plugin, -#endif -#ifdef ENABLE_TWOLAME - &twolame_encoder_plugin, -#endif -#ifdef ENABLE_WAVE_ENCODER - &wave_encoder_plugin, -#endif -#ifdef ENABLE_FLAC_ENCODER - &flac_encoder_plugin, -#endif -#ifdef ENABLE_SHINE - &shine_encoder_plugin, -#endif - nullptr -}; - -const EncoderPlugin * -encoder_plugin_get(const char *name) -{ - for (const auto &plugin : GetAllEncoderPlugins()) { - if (strcmp(plugin.name, name) == 0) - return &plugin; - } - - return nullptr; -} diff --git a/src/encoder/EncoderList.hxx b/src/encoder/EncoderList.hxx index e5c2fe7..515ee5e 100644 --- a/src/encoder/EncoderList.hxx +++ b/src/encoder/EncoderList.hxx @@ -1,27 +1,41 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Copyright The Music Player Daemon Project +// STUB FILE - Encoder support removed for mpd-dbcreate -#pragma once +#ifndef MPD_ENCODER_LIST_HXX +#define MPD_ENCODER_LIST_HXX -#include "util/DereferenceIterator.hxx" -#include "util/TerminatedArray.hxx" +#include struct EncoderPlugin; -extern const EncoderPlugin *const encoder_plugins[]; +/** + * Stub implementation - encoder support not needed for database creation + */ +class EncoderPluginIterator { +public: + using iterator_category = std::forward_iterator_tag; + using value_type = const EncoderPlugin *; + using difference_type = std::ptrdiff_t; + using pointer = value_type *; + using reference = value_type &; -static inline auto -GetAllEncoderPlugins() noexcept + bool operator==(const EncoderPluginIterator &) const noexcept { return true; } + bool operator!=(const EncoderPluginIterator &) const noexcept { return false; } + EncoderPluginIterator &operator++() noexcept { return *this; } + const EncoderPlugin *operator*() const noexcept { return nullptr; } +}; + +inline EncoderPluginIterator +encoder_plugins_begin() noexcept { - return DereferenceContainerAdapter{TerminatedArray{encoder_plugins}}; + return {}; } -/** - * Looks up an encoder plugin by its name. - * - * @param name the encoder name to look for - * @return the encoder plugin with the specified name, or nullptr if none - * was found - */ -const EncoderPlugin * -encoder_plugin_get(const char *name); +inline EncoderPluginIterator +encoder_plugins_end() noexcept +{ + return {}; +} + +#endif diff --git a/src/encoder/EncoderPlugin.hxx b/src/encoder/EncoderPlugin.hxx index 522b3f7..0ebf68e 100644 --- a/src/encoder/EncoderPlugin.hxx +++ b/src/encoder/EncoderPlugin.hxx @@ -1,32 +1,17 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Copyright The Music Player Daemon Project +// STUB FILE - Encoder support removed for mpd-dbcreate #ifndef MPD_ENCODER_PLUGIN_HXX #define MPD_ENCODER_PLUGIN_HXX -class PreparedEncoder; struct ConfigBlock; +/** + * Stub implementation - encoder support not needed for database creation + */ struct EncoderPlugin { const char *name; - - /** - * Throws #std::runtime_error on error. - */ - PreparedEncoder *(*init)(const ConfigBlock &block); }; -/** - * Creates a new encoder object. - * - * Throws #std::runtime_error on error. - * - * @param plugin the encoder plugin - */ -static inline PreparedEncoder * -encoder_init(const EncoderPlugin &plugin, const ConfigBlock &block) -{ - return plugin.init(block); -} - #endif diff --git a/src/encoder/Features.h b/src/encoder/Features.h new file mode 100644 index 0000000..c6ebb58 --- /dev/null +++ b/src/encoder/Features.h @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright The Music Player Daemon Project +// STUB FILE - Encoder support removed for mpd-dbcreate + +#ifndef MPD_ENCODER_FEATURES_H +#define MPD_ENCODER_FEATURES_H + +// Encoder support disabled for database creation tool +#define ENABLE_ENCODER 0 + +#endif diff --git a/src/encoder/ToOutputStream.cxx b/src/encoder/ToOutputStream.cxx deleted file mode 100644 index eec2a7b..0000000 --- a/src/encoder/ToOutputStream.cxx +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#include "ToOutputStream.hxx" -#include "EncoderInterface.hxx" -#include "io/OutputStream.hxx" - -void -EncoderToOutputStream(OutputStream &os, Encoder &encoder) -{ - while (true) { - /* read from the encoder */ - - std::byte buffer[32768]; - const auto r = encoder.Read(buffer); - if (r.empty()) - return; - - /* write everything to the stream */ - - os.Write(r); - } -} diff --git a/src/encoder/ToOutputStream.hxx b/src/encoder/ToOutputStream.hxx deleted file mode 100644 index 503b617..0000000 --- a/src/encoder/ToOutputStream.hxx +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#pragma once - -class OutputStream; -class Encoder; - -/** - * Read all available output from the #Encoder and write it to the - * #OutputStream. - * - * Throws on error. - */ -void -EncoderToOutputStream(OutputStream &os, Encoder &encoder); diff --git a/src/encoder/meson.build b/src/encoder/meson.build deleted file mode 100644 index 2b8ed9f..0000000 --- a/src/encoder/meson.build +++ /dev/null @@ -1,50 +0,0 @@ -encoder_features = configuration_data() - -encoder_features.set('ENABLE_ENCODER', need_encoder) - -if not need_encoder - if need_wave_encoder - # Special case for the Snapcast output plugin which only needs the - # PCM wave encoder encoder plugin - encoder_glue = static_library( - 'encoder_glue', - 'plugins/WaveEncoderPlugin.cxx', - include_directories: inc, - ) - - encoder_glue_dep = declare_dependency( - link_with: encoder_glue, - ) - - configure_file(output: 'Features.h', configuration: encoder_features) - subdir_done() - endif - - encoder_glue_dep = dependency('', required: false) - configure_file(output: 'Features.h', configuration: encoder_features) - subdir_done() -endif - -encoder_api_dep = declare_dependency() - -subdir('plugins') - -encoder_glue = static_library( - 'encoder_glue', - 'Configured.cxx', - 'ToOutputStream.cxx', - 'EncoderList.cxx', - include_directories: inc, - dependencies: [ - fmt_dep, - ], -) - -encoder_glue_dep = declare_dependency( - link_with: encoder_glue, - dependencies: [ - encoder_plugins_dep, - ], -) - -configure_file(output: 'Features.h', configuration: encoder_features) diff --git a/src/encoder/plugins/FlacEncoderPlugin.cxx b/src/encoder/plugins/FlacEncoderPlugin.cxx deleted file mode 100644 index ee6fb12..0000000 --- a/src/encoder/plugins/FlacEncoderPlugin.cxx +++ /dev/null @@ -1,288 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#include "FlacEncoderPlugin.hxx" -#include "../EncoderAPI.hxx" -#include "tag/Names.hxx" -#include "pcm/AudioFormat.hxx" -#include "pcm/Buffer.hxx" -#include "lib/fmt/RuntimeError.hxx" -#include "util/DynamicFifoBuffer.hxx" -#include "util/Serial.hxx" -#include "util/SpanCast.hxx" -#include "util/StringUtil.hxx" - -#include -#include - -#include -#include // for std::unreachable() - -class FlacEncoder final : public Encoder { - const AudioFormat audio_format; - - FLAC__StreamEncoder *const fse; - const unsigned compression; - const bool oggflac; - - PcmBuffer expand_buffer; - - /** - * This buffer will hold encoded data from libFLAC until it is - * picked up with Read(). - */ - DynamicFifoBuffer output_buffer{8192}; - -public: - FlacEncoder(AudioFormat _audio_format, FLAC__StreamEncoder *_fse, unsigned _compression, bool _oggflac, bool _oggchaining); - - ~FlacEncoder() noexcept override { - FLAC__stream_encoder_delete(fse); - } - - FlacEncoder(const FlacEncoder &) = delete; - FlacEncoder &operator=(const FlacEncoder &) = delete; - - /* virtual methods from class Encoder */ - void End() override { - (void) FLAC__stream_encoder_finish(fse); - } - - void Flush() override { - } - - void PreTag() override { - (void) FLAC__stream_encoder_finish(fse); - } - - void SendTag(const Tag &tag) override; - - void Write(std::span src) override; - - std::span Read(std::span) noexcept override { - auto r = output_buffer.Read(); - output_buffer.Consume(r.size()); - return r; - } - -private: - static FLAC__StreamEncoderWriteStatus WriteCallback(const FLAC__StreamEncoder *, - const FLAC__byte data[], - size_t bytes, - [[maybe_unused]] unsigned samples, - [[maybe_unused]] unsigned current_frame, - void *client_data) noexcept { - auto &encoder = *(FlacEncoder *)client_data; - encoder.output_buffer.Append({(const std::byte *)data, bytes}); - return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; - } -}; - -class PreparedFlacEncoder final : public PreparedEncoder { - const unsigned compression; - const bool oggchaining; - const bool oggflac; - -public: - explicit PreparedFlacEncoder(const ConfigBlock &block); - - /* virtual methods from class PreparedEncoder */ - Encoder *Open(AudioFormat &audio_format) override; - - [[nodiscard]] const char *GetMimeType() const noexcept override { - if(oggflac) - return "audio/ogg"; - return "audio/flac"; - } -}; - -PreparedFlacEncoder::PreparedFlacEncoder(const ConfigBlock &block) - :compression(block.GetBlockValue("compression", 5U)), - oggchaining(block.GetBlockValue("oggchaining",false)), - oggflac(block.GetBlockValue("oggflac",false) || oggchaining) -{ -} - -static PreparedEncoder * -flac_encoder_init(const ConfigBlock &block) -{ - return new PreparedFlacEncoder(block); -} - -static void -flac_encoder_setup(FLAC__StreamEncoder *fse, unsigned compression, bool oggflac, - const AudioFormat &audio_format) -{ - unsigned bits_per_sample; - - switch (audio_format.format) { - case SampleFormat::S8: - bits_per_sample = 8; - break; - - case SampleFormat::S16: - bits_per_sample = 16; - break; - - default: - bits_per_sample = 24; - } - - if (!FLAC__stream_encoder_set_compression_level(fse, compression)) - throw FmtRuntimeError("error setting flac compression to {}", - compression); - - if (!FLAC__stream_encoder_set_channels(fse, audio_format.channels)) - throw FmtRuntimeError("error setting flac channels num to {}", - audio_format.channels); - - if (!FLAC__stream_encoder_set_bits_per_sample(fse, bits_per_sample)) - throw FmtRuntimeError("error setting flac bit format to {}", - bits_per_sample); - - if (!FLAC__stream_encoder_set_sample_rate(fse, - audio_format.sample_rate)) - throw FmtRuntimeError("error setting flac sample rate to {}", - audio_format.sample_rate); - - if (oggflac && !FLAC__stream_encoder_set_ogg_serial_number(fse, - GenerateSerial())) - throw std::runtime_error{"error setting ogg serial number"}; -} - -FlacEncoder::FlacEncoder(AudioFormat _audio_format, FLAC__StreamEncoder *_fse, unsigned _compression, bool _oggflac, bool _oggchaining) - :Encoder(_oggchaining), - audio_format(_audio_format), fse(_fse), - compression(_compression), - oggflac(_oggflac) -{ - /* this immediately outputs data through callback */ - - auto init_status = oggflac ? - FLAC__stream_encoder_init_ogg_stream(fse, - nullptr, WriteCallback, - nullptr, nullptr, nullptr, - this) - : - FLAC__stream_encoder_init_stream(fse, - WriteCallback, - nullptr, nullptr, nullptr, - this); - - if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) - throw FmtRuntimeError("failed to initialize encoder: {}", - FLAC__StreamEncoderInitStatusString[init_status]); -} - -Encoder * -PreparedFlacEncoder::Open(AudioFormat &audio_format) -{ - switch (audio_format.format) { - case SampleFormat::S8: - break; - - case SampleFormat::S16: - break; - - case SampleFormat::S24_P32: - break; - - default: - audio_format.format = SampleFormat::S24_P32; - } - - /* allocate the encoder */ - auto fse = FLAC__stream_encoder_new(); - if (fse == nullptr) - throw std::runtime_error("FLAC__stream_encoder_new() failed"); - - try { - flac_encoder_setup(fse, compression, oggflac, audio_format); - } catch (...) { - FLAC__stream_encoder_delete(fse); - throw; - } - - return new FlacEncoder(audio_format, fse, compression, oggflac, oggchaining); -} - -void -FlacEncoder::SendTag(const Tag &tag) -{ - /* re-initialize encoder since flac_encoder_finish resets everything */ - flac_encoder_setup(fse, compression, oggflac, audio_format); - - FLAC__StreamMetadata *metadata = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT); - FLAC__StreamMetadata_VorbisComment_Entry entry; - - for (const auto &item : tag) { - char name[64]; - ToUpperASCII(name, tag_item_names[item.type], sizeof(name)); - FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, name, item.value); - FLAC__metadata_object_vorbiscomment_append_comment(metadata, entry, false); - } - - FLAC__stream_encoder_set_metadata(fse,&metadata,1); - - auto init_status = FLAC__stream_encoder_init_ogg_stream(fse, - nullptr, WriteCallback, - nullptr, nullptr, nullptr, - this); - - FLAC__metadata_object_delete(metadata); - - if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) - throw FmtRuntimeError("failed to initialize encoder: {}", - FLAC__StreamEncoderInitStatusString[init_status]); -} - -template -static std::span -ToFlac32(PcmBuffer &buffer, std::span src) noexcept -{ - FLAC__int32 *dest = buffer.GetT(src.size()); - std::copy(src.begin(), src.end(), dest); - return {dest, src.size()}; -} - -static std::span -ToFlac32(PcmBuffer &buffer, std::span src, - SampleFormat format) -{ - switch (format) { - case SampleFormat::S8: - return ToFlac32(buffer, FromBytesStrict(src)); - - case SampleFormat::S16: - return ToFlac32(buffer, FromBytesStrict(src)); - - case SampleFormat::S24_P32: - case SampleFormat::S32: - /* nothing need to be done; format is the same for - both mpd and libFLAC */ - return FromBytesStrict(src); - - default: - std::unreachable(); - } -} - -void -FlacEncoder::Write(std::span src) -{ - const auto imported = ToFlac32(expand_buffer, src, - audio_format.format); - const std::size_t n_frames = imported.size() / audio_format.channels; - - /* feed samples to encoder */ - - if (!FLAC__stream_encoder_process_interleaved(fse, imported.data(), - n_frames)) - throw std::runtime_error("flac encoder process failed"); -} - -const EncoderPlugin flac_encoder_plugin = { - "flac", - flac_encoder_init, -}; - diff --git a/src/encoder/plugins/FlacEncoderPlugin.hxx b/src/encoder/plugins/FlacEncoderPlugin.hxx deleted file mode 100644 index 090232c..0000000 --- a/src/encoder/plugins/FlacEncoderPlugin.hxx +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#ifndef MPD_ENCODER_FLAC_HXX -#define MPD_ENCODER_FLAC_HXX - -extern const struct EncoderPlugin flac_encoder_plugin; - -#endif diff --git a/src/encoder/plugins/LameEncoderPlugin.cxx b/src/encoder/plugins/LameEncoderPlugin.cxx deleted file mode 100644 index ced087c..0000000 --- a/src/encoder/plugins/LameEncoderPlugin.cxx +++ /dev/null @@ -1,187 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#include "LameEncoderPlugin.hxx" -#include "../EncoderAPI.hxx" -#include "pcm/AudioFormat.hxx" -#include "lib/fmt/RuntimeError.hxx" -#include "util/CNumberParser.hxx" -#include "util/ReusableArray.hxx" -#include "util/SpanCast.hxx" - -#include - -#include -#include - -class LameEncoder final : public Encoder { - lame_global_flags *const gfp; - - ReusableArray output_buffer; - std::span output{}; - -public: - static constexpr unsigned CHANNELS = 2; - - explicit LameEncoder(lame_global_flags *_gfp) noexcept - :Encoder(false), gfp(_gfp) {} - - ~LameEncoder() noexcept override; - - LameEncoder(const LameEncoder &) = delete; - LameEncoder &operator=(const LameEncoder &) = delete; - - /* virtual methods from class Encoder */ - void Write(std::span src) override; - std::span Read(std::span buffer) noexcept override; -}; - -class PreparedLameEncoder final : public PreparedEncoder { - float quality; - int bitrate; - -public: - explicit PreparedLameEncoder(const ConfigBlock &block); - - /* virtual methods from class PreparedEncoder */ - Encoder *Open(AudioFormat &audio_format) override; - - [[nodiscard]] const char *GetMimeType() const noexcept override { - return "audio/mpeg"; - } -}; - -PreparedLameEncoder::PreparedLameEncoder(const ConfigBlock &block) -{ - const char *value; - char *endptr; - - value = block.GetBlockValue("quality"); - if (value != nullptr) { - /* a quality was configured (VBR) */ - - quality = float(ParseDouble(value, &endptr)); - - if (*endptr != '\0' || quality < -1.0f || quality > 10.0f) - throw FmtRuntimeError("quality {:?} is not a number in the " - "range -1 to 10", - value); - - if (block.GetBlockValue("bitrate") != nullptr) - throw std::runtime_error("quality and bitrate are both defined"); - } else { - /* a bit rate was configured */ - - value = block.GetBlockValue("bitrate"); - if (value == nullptr) - throw std::runtime_error("neither bitrate nor quality defined"); - - quality = -2.0; - bitrate = ParseInt(value, &endptr); - - if (*endptr != '\0' || bitrate <= 0) - throw std::runtime_error("bitrate should be a positive integer"); - } -} - -static PreparedEncoder * -lame_encoder_init(const ConfigBlock &block) -{ - return new PreparedLameEncoder(block); -} - -static void -lame_encoder_setup(lame_global_flags *gfp, float quality, int bitrate, - const AudioFormat &audio_format) -{ - if (quality >= -1.0f) { - /* a quality was configured (VBR) */ - - if (0 != lame_set_VBR(gfp, vbr_rh)) - throw std::runtime_error("error setting lame VBR mode"); - - if (0 != lame_set_VBR_q(gfp, int(quality))) - throw std::runtime_error("error setting lame VBR quality"); - } else { - /* a bit rate was configured */ - - if (0 != lame_set_brate(gfp, bitrate)) - throw std::runtime_error("error setting lame bitrate"); - } - - if (0 != lame_set_num_channels(gfp, audio_format.channels)) - throw std::runtime_error("error setting lame num channels"); - - if (0 != lame_set_in_samplerate(gfp, audio_format.sample_rate)) - throw std::runtime_error("error setting lame sample rate"); - - if (0 != lame_set_out_samplerate(gfp, audio_format.sample_rate)) - throw std::runtime_error("error setting lame out sample rate"); - - if (0 > lame_init_params(gfp)) - throw std::runtime_error("error initializing lame params"); -} - -Encoder * -PreparedLameEncoder::Open(AudioFormat &audio_format) -{ - audio_format.format = SampleFormat::S16; - audio_format.channels = LameEncoder::CHANNELS; - - auto gfp = lame_init(); - if (gfp == nullptr) - throw std::runtime_error("lame_init() failed"); - - try { - lame_encoder_setup(gfp, quality, bitrate, audio_format); - } catch (...) { - lame_close(gfp); - throw; - } - - return new LameEncoder(gfp); -} - -LameEncoder::~LameEncoder() noexcept -{ - lame_close(gfp); -} - -void -LameEncoder::Write(std::span _src) -{ - const auto src = FromBytesStrict(_src); - - assert(output.empty()); - - const std::size_t num_samples = src.size(); - const std::size_t num_frames = num_samples / CHANNELS; - - /* worst-case formula according to LAME documentation */ - const std::size_t output_buffer_size = 5 * num_samples / 4 + 7200; - const auto dest = output_buffer.Get(output_buffer_size); - - /* this is for only 16-bit audio */ - - int bytes_out = lame_encode_buffer_interleaved(gfp, - const_cast(src.data()), - num_frames, - (unsigned char *)dest, - output_buffer_size); - - if (bytes_out < 0) - throw std::runtime_error("lame encoder failed"); - - output = {dest, std::size_t(bytes_out)}; -} - -std::span -LameEncoder::Read(std::span) noexcept -{ - return std::exchange(output, std::span{}); -} - -const EncoderPlugin lame_encoder_plugin = { - "lame", - lame_encoder_init, -}; diff --git a/src/encoder/plugins/LameEncoderPlugin.hxx b/src/encoder/plugins/LameEncoderPlugin.hxx deleted file mode 100644 index dad802e..0000000 --- a/src/encoder/plugins/LameEncoderPlugin.hxx +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#ifndef MPD_ENCODER_LAME_HXX -#define MPD_ENCODER_LAME_HXX - -extern const struct EncoderPlugin lame_encoder_plugin; - -#endif diff --git a/src/encoder/plugins/NullEncoderPlugin.cxx b/src/encoder/plugins/NullEncoderPlugin.cxx deleted file mode 100644 index e45cc65..0000000 --- a/src/encoder/plugins/NullEncoderPlugin.cxx +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#include "NullEncoderPlugin.hxx" -#include "../EncoderAPI.hxx" -#include "util/DynamicFifoBuffer.hxx" - -class NullEncoder final : public Encoder { - DynamicFifoBuffer buffer{8192}; - -public: - NullEncoder() - :Encoder(false) {} - - /* virtual methods from class Encoder */ - void Write(std::span src) override { - buffer.Append(src); - } - - std::span Read(std::span b) noexcept override { - return b.first(buffer.Read(b.data(), b.size())); - } -}; - -class PreparedNullEncoder final : public PreparedEncoder { -public: - /* virtual methods from class PreparedEncoder */ - Encoder *Open(AudioFormat &) override { - return new NullEncoder(); - } -}; - -static PreparedEncoder * -null_encoder_init([[maybe_unused]] const ConfigBlock &block) -{ - return new PreparedNullEncoder(); -} - -const EncoderPlugin null_encoder_plugin = { - "null", - null_encoder_init, -}; diff --git a/src/encoder/plugins/NullEncoderPlugin.hxx b/src/encoder/plugins/NullEncoderPlugin.hxx deleted file mode 100644 index c468a25..0000000 --- a/src/encoder/plugins/NullEncoderPlugin.hxx +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#ifndef MPD_ENCODER_NULL_HXX -#define MPD_ENCODER_NULL_HXX - -extern const struct EncoderPlugin null_encoder_plugin; - -#endif diff --git a/src/encoder/plugins/OggEncoder.hxx b/src/encoder/plugins/OggEncoder.hxx deleted file mode 100644 index 3dda457..0000000 --- a/src/encoder/plugins/OggEncoder.hxx +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#ifndef MPD_OGG_ENCODER_HXX -#define MPD_OGG_ENCODER_HXX - -#include "../EncoderAPI.hxx" -#include "lib/xiph/OggStreamState.hxx" -#include "lib/xiph/OggPage.hxx" -#include "util/Serial.hxx" - -#include - -/** - * An abstract base class which contains code common to all encoders - * with Ogg container output. - */ -class OggEncoder : public Encoder { - /* initialize "flush" to true, so the caller gets the full - headers on the first read */ - bool flush = true; - -protected: - OggStreamState stream; - -public: - OggEncoder(bool _implements_tag) - :Encoder(_implements_tag), - stream(GenerateSerial()) { - } - - /* virtual methods from class Encoder */ - void Flush() final { - flush = true; - } - - std::span Read(std::span buffer) noexcept override { - ogg_page page; - bool success = stream.PageOut(page); - if (!success) { - if (flush) { - flush = false; - success = stream.Flush(page); - } - - if (!success) - return {}; - } - - return buffer.first(ReadPage(page, buffer.data(), - buffer.size())); - } -}; - -#endif diff --git a/src/encoder/plugins/OpusEncoderPlugin.cxx b/src/encoder/plugins/OpusEncoderPlugin.cxx deleted file mode 100644 index 117ad8b..0000000 --- a/src/encoder/plugins/OpusEncoderPlugin.cxx +++ /dev/null @@ -1,402 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#include "OpusEncoderPlugin.hxx" -#include "OggEncoder.hxx" -#include "tag/Names.hxx" -#include "pcm/AudioFormat.hxx" -#include "util/ByteOrder.hxx" -#include "util/StringUtil.hxx" - -#include -#include - -#include -#include - -#include - -namespace { - -class OpusEncoder final : public OggEncoder { - const AudioFormat audio_format; - - const size_t frame_size; - - const size_t buffer_frames, buffer_size; - size_t buffer_position = 0; - std::byte *const buffer; - - ::OpusEncoder *const enc; - - unsigned char buffer2[1275 * 3 + 7]; - - int lookahead; - - ogg_int64_t packetno = 0; - - ogg_int64_t granulepos = 0; - -public: - OpusEncoder(AudioFormat &_audio_format, ::OpusEncoder *_enc, bool _chaining); - ~OpusEncoder() noexcept override; - - OpusEncoder(const OpusEncoder &) = delete; - OpusEncoder &operator=(const OpusEncoder &) = delete; - - /* virtual methods from class Encoder */ - void End() override; - void Write(std::span src) override; - - void PreTag() override; - void SendTag(const Tag &tag) override; - -private: - void DoEncode(bool eos); - void WriteSilence(unsigned fill_frames); - - void GenerateHeaders(const Tag *tag) noexcept; - void GenerateHead() noexcept; - void GenerateTags(const Tag *tag) noexcept; -}; - -class PreparedOpusEncoder final : public PreparedEncoder { - opus_int32 bitrate; - int complexity; - int signal; - int packet_loss; - int vbr; - int vbr_constraint; - const bool chaining; - -public: - explicit PreparedOpusEncoder(const ConfigBlock &block); - - /* virtual methods from class PreparedEncoder */ - Encoder *Open(AudioFormat &audio_format) override; - - [[nodiscard]] const char *GetMimeType() const noexcept override { - return "audio/ogg"; - } -}; - -PreparedOpusEncoder::PreparedOpusEncoder(const ConfigBlock &block) - :chaining(block.GetBlockValue("opustags", false)) -{ - const char *value = block.GetBlockValue("bitrate", "auto"); - if (strcmp(value, "auto") == 0) - bitrate = OPUS_AUTO; - else if (strcmp(value, "max") == 0) - bitrate = OPUS_BITRATE_MAX; - else { - char *endptr; - bitrate = strtoul(value, &endptr, 10); - if (endptr == value || *endptr != 0 || - bitrate < 500 || bitrate > 512000) - throw std::runtime_error("Invalid bit rate"); - } - - complexity = block.GetBlockValue("complexity", 10U); - if (complexity > 10) - throw std::runtime_error("Invalid complexity"); - - value = block.GetBlockValue("signal", "auto"); - if (strcmp(value, "auto") == 0) - signal = OPUS_AUTO; - else if (strcmp(value, "voice") == 0) - signal = OPUS_SIGNAL_VOICE; - else if (strcmp(value, "music") == 0) - signal = OPUS_SIGNAL_MUSIC; - else - throw std::runtime_error("Invalid signal"); - - value = block.GetBlockValue("vbr", "yes"); - if (strcmp(value, "yes") == 0) { - vbr = 1U; - vbr_constraint = 0U; - } else if (strcmp(value, "no") == 0) { - vbr = 0U; - vbr_constraint = 0U; - } else if (strcmp(value, "constrained") == 0) { - vbr = 1U; - vbr_constraint = 1U; - } else - throw std::runtime_error("Invalid vbr"); - - packet_loss = block.GetBlockValue("packet_loss", 0U); - if (packet_loss > 100) - throw std::runtime_error("Invalid packet loss"); -} - -PreparedEncoder * -opus_encoder_init(const ConfigBlock &block) -{ - return new PreparedOpusEncoder(block); -} - -OpusEncoder::OpusEncoder(AudioFormat &_audio_format, ::OpusEncoder *_enc, bool _chaining) - :OggEncoder(_chaining), - audio_format(_audio_format), - frame_size(_audio_format.GetFrameSize()), - buffer_frames(_audio_format.sample_rate / 50), - buffer_size(frame_size * buffer_frames), - buffer(new std::byte[buffer_size]), - enc(_enc) -{ - opus_encoder_ctl(enc, OPUS_GET_LOOKAHEAD(&lookahead)); - GenerateHeaders(nullptr); -} - -Encoder * -PreparedOpusEncoder::Open(AudioFormat &audio_format) -{ - /* libopus supports only 48 kHz */ - audio_format.sample_rate = 48000; - - if (audio_format.channels > 2) - audio_format.channels = 1; - - switch (audio_format.format) { - case SampleFormat::S16: - case SampleFormat::FLOAT: - break; - - case SampleFormat::S8: - audio_format.format = SampleFormat::S16; - break; - - default: - audio_format.format = SampleFormat::FLOAT; - break; - } - - int error_code; - auto *enc = opus_encoder_create(audio_format.sample_rate, - audio_format.channels, - OPUS_APPLICATION_AUDIO, - &error_code); - if (enc == nullptr) - throw std::runtime_error(opus_strerror(error_code)); - - opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate)); - opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity)); - opus_encoder_ctl(enc, OPUS_SET_SIGNAL(signal)); - opus_encoder_ctl(enc, OPUS_SET_VBR(vbr)); - opus_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(vbr_constraint)); - opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(packet_loss)); - - return new OpusEncoder(audio_format, enc, chaining); -} - -OpusEncoder::~OpusEncoder() noexcept -{ - delete[] buffer; - opus_encoder_destroy(enc); -} - -void -OpusEncoder::DoEncode(bool eos) -{ - assert(buffer_position == buffer_size || eos); - - opus_int32 result = - audio_format.format == SampleFormat::S16 - ? opus_encode(enc, - (const opus_int16 *)buffer, - buffer_frames, - buffer2, - sizeof(buffer2)) - : opus_encode_float(enc, - (const float *)buffer, - buffer_frames, - buffer2, - sizeof(buffer2)); - if (result < 0) - throw std::runtime_error("Opus encoder error"); - - granulepos += buffer_position / frame_size; - - ogg_packet packet; - packet.packet = buffer2; - packet.bytes = result; - packet.b_o_s = false; - packet.e_o_s = eos; - packet.granulepos = granulepos; - packet.packetno = packetno++; - stream.PacketIn(packet); - - buffer_position = 0; -} - -void -OpusEncoder::End() -{ - memset(buffer + buffer_position, 0, - buffer_size - buffer_position); - DoEncode(true); - Flush(); -} - -void -OpusEncoder::WriteSilence(unsigned fill_frames) -{ - size_t fill_bytes = fill_frames * frame_size; - - while (fill_bytes > 0) { - size_t nbytes = buffer_size - buffer_position; - if (nbytes > fill_bytes) - nbytes = fill_bytes; - - memset(buffer + buffer_position, 0, nbytes); - buffer_position += nbytes; - fill_bytes -= nbytes; - - if (buffer_position == buffer_size) - DoEncode(false); - } -} - -void -OpusEncoder::Write(std::span src) -{ - if (lookahead > 0) { - /* generate some silence at the beginning of the - stream */ - - assert(buffer_position == 0); - - WriteSilence(lookahead); - lookahead = 0; - } - - while (!src.empty()) { - const std::size_t nbytes = std::min(buffer_size - buffer_position, - src.size()); - - memcpy(buffer + buffer_position, src.data(), nbytes); - src = src.subspan(nbytes); - buffer_position += nbytes; - - if (buffer_position == buffer_size) - DoEncode(false); - } -} - -void -OpusEncoder::GenerateHeaders(const Tag *tag) noexcept -{ - GenerateHead(); - GenerateTags(tag); -} - -void -OpusEncoder::GenerateHead() noexcept -{ - unsigned char header[19]; - memcpy(header, "OpusHead", 8); - header[8] = 1; - header[9] = audio_format.channels; - *(uint16_t *)(header + 10) = ToLE16(lookahead); - *(uint32_t *)(header + 12) = ToLE32(audio_format.sample_rate); - header[16] = 0; - header[17] = 0; - header[18] = 0; - - ogg_packet packet; - packet.packet = header; - packet.bytes = sizeof(header); - packet.b_o_s = true; - packet.e_o_s = false; - packet.granulepos = 0; - packet.packetno = packetno++; - stream.PacketIn(packet); - // flush not needed because libogg autoflushes on b_o_s flag -} - -void -OpusEncoder::GenerateTags(const Tag *tag) noexcept -{ - const char *version = opus_get_version_string(); - size_t version_length = strlen(version); - - // len("OpusTags") + 4 byte version length + len(version) + 4 byte tag count - size_t comments_size = 8 + 4 + version_length + 4; - uint32_t tag_count = 0; - if (tag) { - for (const auto &item: *tag) { - ++tag_count; - // 4 byte length + len(tagname) + len('=') + len(value) - comments_size += 4 + strlen(tag_item_names[item.type]) + 1 + strlen(item.value); - } - } - - auto *comments = new unsigned char[comments_size]; - unsigned char *p = comments; - - memcpy(comments, "OpusTags", 8); - *(uint32_t *)(comments + 8) = ToLE32(version_length); - p += 12; - - memcpy(p, version, version_length); - p += version_length; - - tag_count = ToLE32(tag_count); - memcpy(p, &tag_count, 4); - p += 4; - - if (tag) { - for (const auto &item: *tag) { - size_t tag_name_len = strlen(tag_item_names[item.type]); - size_t tag_val_len = strlen(item.value); - uint32_t tag_len_le = ToLE32(tag_name_len + 1 + tag_val_len); - - memcpy(p, &tag_len_le, 4); - p += 4; - - ToUpperASCII((char *)p, tag_item_names[item.type], tag_name_len + 1); - p += tag_name_len; - - *p++ = '='; - - memcpy(p, item.value, tag_val_len); - p += tag_val_len; - } - } - assert(comments + comments_size == p); - - ogg_packet packet; - packet.packet = comments; - packet.bytes = comments_size; - packet.b_o_s = false; - packet.e_o_s = false; - packet.granulepos = 0; - packet.packetno = packetno++; - stream.PacketIn(packet); - Flush(); - - delete[] comments; -} - -void -OpusEncoder::PreTag() -{ - End(); - packetno = 0; - granulepos = 0; // not really required, but useful to prevent wraparound - opus_encoder_ctl(enc, OPUS_RESET_STATE); -} - -void -OpusEncoder::SendTag(const Tag &tag) -{ - stream.Reinitialize(GenerateSerial()); - opus_encoder_ctl(enc, OPUS_GET_LOOKAHEAD(&lookahead)); - GenerateHeaders(&tag); -} - -} // namespace - -const EncoderPlugin opus_encoder_plugin = { - "opus", - opus_encoder_init, -}; diff --git a/src/encoder/plugins/OpusEncoderPlugin.hxx b/src/encoder/plugins/OpusEncoderPlugin.hxx deleted file mode 100644 index 14fc7e5..0000000 --- a/src/encoder/plugins/OpusEncoderPlugin.hxx +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#ifndef MPD_ENCODER_OPUS_H -#define MPD_ENCODER_OPUS_H - -extern const struct EncoderPlugin opus_encoder_plugin; - -#endif diff --git a/src/encoder/plugins/ShineEncoderPlugin.cxx b/src/encoder/plugins/ShineEncoderPlugin.cxx deleted file mode 100644 index 9453b6a..0000000 --- a/src/encoder/plugins/ShineEncoderPlugin.cxx +++ /dev/null @@ -1,193 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#include "ShineEncoderPlugin.hxx" -#include "../EncoderAPI.hxx" -#include "pcm/AudioFormat.hxx" -#include "lib/fmt/RuntimeError.hxx" -#include "util/DynamicFifoBuffer.hxx" -#include "util/SpanCast.hxx" - -extern "C" -{ -#include -} - -static constexpr size_t BUFFER_INIT_SIZE = 8192; -static constexpr unsigned CHANNELS = 2; - -class ShineEncoder final : public Encoder { - const AudioFormat audio_format; - - const shine_t shine; - - const size_t frame_size; - - /* workaround for bug: - https://github.com/savonet/shine/issues/11 */ - size_t input_pos = SHINE_MAX_SAMPLES + 1; - - int16_t *stereo[CHANNELS]; - - DynamicFifoBuffer output_buffer{BUFFER_INIT_SIZE}; - -public: - ShineEncoder(AudioFormat _audio_format, shine_t _shine) noexcept - :Encoder(false), - audio_format(_audio_format), shine(_shine), - frame_size(shine_samples_per_pass(shine)), - stereo{new int16_t[frame_size], new int16_t[frame_size]} - {} - - ~ShineEncoder() noexcept override { - if (input_pos > SHINE_MAX_SAMPLES) { - /* write zero chunk */ - input_pos = 0; - WriteChunk(true); - } - - shine_close(shine); - delete[] stereo[0]; - delete[] stereo[1]; - } - - bool WriteChunk(bool flush); - - /* virtual methods from class Encoder */ - void End() override { - return Flush(); - } - - void Flush() override; - - void Write(std::span src) override; - - std::span Read(std::span buffer) noexcept override { - return buffer.first(output_buffer.Read(buffer.data(), buffer.size())); - } -}; - -class PreparedShineEncoder final : public PreparedEncoder { - shine_config_t config; - -public: - explicit PreparedShineEncoder(const ConfigBlock &block); - - /* virtual methods from class PreparedEncoder */ - Encoder *Open(AudioFormat &audio_format) override; - - [[nodiscard]] const char *GetMimeType() const noexcept override { - return "audio/mpeg"; - } -}; - -PreparedShineEncoder::PreparedShineEncoder(const ConfigBlock &block) -{ - shine_set_config_mpeg_defaults(&config.mpeg); - config.mpeg.bitr = block.GetBlockValue("bitrate", 128); -} - -static PreparedEncoder * -shine_encoder_init(const ConfigBlock &block) -{ - return new PreparedShineEncoder(block); -} - -static shine_t -SetupShine(shine_config_t config, AudioFormat &audio_format) -{ - audio_format.format = SampleFormat::S16; - audio_format.channels = CHANNELS; - - config.mpeg.mode = audio_format.channels == 2 ? STEREO : MONO; - config.wave.samplerate = audio_format.sample_rate; - config.wave.channels = - audio_format.channels == 2 ? PCM_STEREO : PCM_MONO; - - if (shine_check_config(config.wave.samplerate, config.mpeg.bitr) < 0) - throw FmtRuntimeError("error configuring shine. " - "samplerate {} and bitrate {} configuration" - " not supported.", - config.wave.samplerate, - config.mpeg.bitr); - - auto shine = shine_initialise(&config); - if (!shine) - throw std::runtime_error("error initializing shine"); - - return shine; -} - -Encoder * -PreparedShineEncoder::Open(AudioFormat &audio_format) -{ - auto shine = SetupShine(config, audio_format); - return new ShineEncoder(audio_format, shine); -} - -bool -ShineEncoder::WriteChunk(bool flush) -{ - if (flush || input_pos == frame_size) { - if (flush) { - /* fill remaining with 0s */ - for (; input_pos < frame_size; input_pos++) { - stereo[0][input_pos] = stereo[1][input_pos] = 0; - } - } - - int written; - const auto out = (const std::byte *) - shine_encode_buffer(shine, stereo, &written); - - if (written > 0) - output_buffer.Append({out, std::size_t(written)}); - - input_pos = 0; - } - - return true; -} - -void -ShineEncoder::Write(std::span _src) -{ - const auto src = FromBytesStrict(_src); - const std::size_t nframes = src.size() / audio_format.channels; - size_t written = 0; - - if (input_pos > SHINE_MAX_SAMPLES) - input_pos = 0; - - /* write all data to de-interleaved buffers */ - while (written < nframes) { - for (; - written < nframes && input_pos < frame_size; - written++, input_pos++) { - const size_t base = - written * audio_format.channels; - stereo[0][input_pos] = src[base]; - stereo[1][input_pos] = src[base + 1]; - } - /* write if chunk is filled */ - WriteChunk(false); - } -} - -void -ShineEncoder::Flush() -{ - /* flush buffers and flush shine */ - WriteChunk(true); - - int written; - const auto data = (const std::byte *)shine_flush(shine, &written); - - if (written > 0) - output_buffer.Append({data, std::size_t(written)}); -} - -const EncoderPlugin shine_encoder_plugin = { - "shine", - shine_encoder_init, -}; diff --git a/src/encoder/plugins/ShineEncoderPlugin.hxx b/src/encoder/plugins/ShineEncoderPlugin.hxx deleted file mode 100644 index 57c987e..0000000 --- a/src/encoder/plugins/ShineEncoderPlugin.hxx +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#ifndef MPD_ENCODER_SHINE_HXX -#define MPD_ENCODER_SHINE_HXX - -extern const struct EncoderPlugin shine_encoder_plugin; - -#endif diff --git a/src/encoder/plugins/TwolameEncoderPlugin.cxx b/src/encoder/plugins/TwolameEncoderPlugin.cxx deleted file mode 100644 index 2463c41..0000000 --- a/src/encoder/plugins/TwolameEncoderPlugin.cxx +++ /dev/null @@ -1,209 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#include "TwolameEncoderPlugin.hxx" -#include "../EncoderAPI.hxx" -#include "pcm/AudioFormat.hxx" -#include "lib/fmt/RuntimeError.hxx" -#include "util/CNumberParser.hxx" -#include "util/SpanCast.hxx" -#include "util/Domain.hxx" -#include "Log.hxx" - -#include - -#include -#include - -class TwolameEncoder final : public Encoder { - twolame_options *options; - - std::byte output_buffer[32768]; - std::size_t fill = 0; - - /** - * Call libtwolame's flush function when the output_buffer is - * empty? - */ - bool flush = false; - -public: - static constexpr unsigned CHANNELS = 2; - - explicit TwolameEncoder(twolame_options *_options) noexcept - :Encoder(false), options(_options) {} - ~TwolameEncoder() noexcept override; - - TwolameEncoder(const TwolameEncoder &) = delete; - TwolameEncoder &operator=(const TwolameEncoder &) = delete; - - /* virtual methods from class Encoder */ - - void End() override { - flush = true; - } - - void Flush() override { - flush = true; - } - - void Write(std::span src) override; - std::span Read(std::span buffer) noexcept override; -}; - -class PreparedTwolameEncoder final : public PreparedEncoder { - float quality; - int bitrate; - -public: - explicit PreparedTwolameEncoder(const ConfigBlock &block); - - /* virtual methods from class PreparedEncoder */ - Encoder *Open(AudioFormat &audio_format) override; - - [[nodiscard]] const char *GetMimeType() const noexcept override { - return "audio/mpeg"; - } -}; - -static constexpr Domain twolame_encoder_domain("twolame_encoder"); - -PreparedTwolameEncoder::PreparedTwolameEncoder(const ConfigBlock &block) -{ - const char *value; - char *endptr; - - value = block.GetBlockValue("quality"); - if (value != nullptr) { - /* a quality was configured (VBR) */ - - quality = float(ParseDouble(value, &endptr)); - - if (*endptr != '\0' || quality < -1.0f || quality > 10.0f) - throw FmtRuntimeError("quality {:?} is not a number in the " - "range -1 to 10", - value); - - if (block.GetBlockValue("bitrate") != nullptr) - throw std::runtime_error("quality and bitrate are both defined"); - } else { - /* a bit rate was configured */ - - value = block.GetBlockValue("bitrate"); - if (value == nullptr) - throw std::runtime_error("neither bitrate nor quality defined"); - - quality = -2.0; - bitrate = ParseInt(value, &endptr); - - if (*endptr != '\0' || bitrate <= 0) - throw std::runtime_error("bitrate should be a positive integer"); - } -} - -static PreparedEncoder * -twolame_encoder_init(const ConfigBlock &block) -{ - FmtDebug(twolame_encoder_domain, - "libtwolame version {}", get_twolame_version()); - - return new PreparedTwolameEncoder(block); -} - -static void -twolame_encoder_setup(twolame_options *options, float quality, int bitrate, - const AudioFormat &audio_format) -{ - if (quality >= -1.0f) { - /* a quality was configured (VBR) */ - - if (0 != twolame_set_VBR(options, true)) - throw std::runtime_error("error setting twolame VBR mode"); - - if (0 != twolame_set_VBR_q(options, quality)) - throw std::runtime_error("error setting twolame VBR quality"); - } else { - /* a bit rate was configured */ - - if (0 != twolame_set_brate(options, bitrate)) - throw std::runtime_error("error setting twolame bitrate"); - } - - if (0 != twolame_set_num_channels(options, audio_format.channels)) - throw std::runtime_error("error setting twolame num channels"); - - if (0 != twolame_set_in_samplerate(options, - audio_format.sample_rate)) - throw std::runtime_error("error setting twolame sample rate"); - - if (0 > twolame_init_params(options)) - throw std::runtime_error("error initializing twolame params"); -} - -Encoder * -PreparedTwolameEncoder::Open(AudioFormat &audio_format) -{ - audio_format.format = SampleFormat::S16; - audio_format.channels = TwolameEncoder::CHANNELS; - - auto options = twolame_init(); - if (options == nullptr) - throw std::runtime_error("twolame_init() failed"); - - try { - twolame_encoder_setup(options, quality, bitrate, - audio_format); - } catch (...) { - twolame_close(&options); - throw; - } - - return new TwolameEncoder(options); -} - -TwolameEncoder::~TwolameEncoder() noexcept -{ - twolame_close(&options); -} - -void -TwolameEncoder::Write(std::span _src) -{ - const auto src = FromBytesStrict(_src); - - assert(fill == 0); - - const std::size_t num_frames = src.size() / CHANNELS; - - int bytes_out = twolame_encode_buffer_interleaved(options, - src.data(), num_frames, - (unsigned char *)output_buffer, - sizeof(output_buffer)); - if (bytes_out < 0) - throw std::runtime_error("twolame encoder failed"); - - fill = (std::size_t)bytes_out; -} - -std::span -TwolameEncoder::Read(std::span) noexcept -{ - assert(fill <= sizeof(output_buffer)); - - if (fill == 0 && flush) { - int ret = twolame_encode_flush(options, - (unsigned char *)output_buffer, - sizeof(output_buffer)); - if (ret > 0) - fill = (std::size_t)ret; - - flush = false; - } - - return std::span{output_buffer}.first(std::exchange(fill, 0)); -} - -const EncoderPlugin twolame_encoder_plugin = { - "twolame", - twolame_encoder_init, -}; diff --git a/src/encoder/plugins/TwolameEncoderPlugin.hxx b/src/encoder/plugins/TwolameEncoderPlugin.hxx deleted file mode 100644 index d9afe7a..0000000 --- a/src/encoder/plugins/TwolameEncoderPlugin.hxx +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#ifndef MPD_ENCODER_TWOLAME_HXX -#define MPD_ENCODER_TWOLAME_HXX - -extern const struct EncoderPlugin twolame_encoder_plugin; - -#endif diff --git a/src/encoder/plugins/VorbisEncoderPlugin.cxx b/src/encoder/plugins/VorbisEncoderPlugin.cxx deleted file mode 100644 index 7d0cd82..0000000 --- a/src/encoder/plugins/VorbisEncoderPlugin.cxx +++ /dev/null @@ -1,251 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#include "VorbisEncoderPlugin.hxx" -#include "OggEncoder.hxx" -#include "lib/fmt/RuntimeError.hxx" -#include "lib/xiph/VorbisComment.hxx" -#include "tag/Names.hxx" -#include "pcm/AudioFormat.hxx" -#include "config/Domain.hxx" -#include "util/StringUtil.hxx" -#include "util/CNumberParser.hxx" - -#include - -class VorbisEncoder final : public OggEncoder { - AudioFormat audio_format; - - vorbis_dsp_state vd; - vorbis_block vb; - vorbis_info vi; - -public: - VorbisEncoder(float quality, int bitrate, AudioFormat &_audio_format); - - ~VorbisEncoder() noexcept override { - vorbis_block_clear(&vb); - vorbis_dsp_clear(&vd); - vorbis_info_clear(&vi); - } - - VorbisEncoder(const VorbisEncoder &) = delete; - VorbisEncoder &operator=(const VorbisEncoder &) = delete; - - /* virtual methods from class Encoder */ - void End() override { - PreTag(); - } - - void PreTag() override; - void SendTag(const Tag &tag) override; - - void Write(std::span src) override; - -private: - void HeaderOut(vorbis_comment &vc); - void SendHeader(); - void BlockOut(); -}; - -class PreparedVorbisEncoder final : public PreparedEncoder { - float quality = 3; - int bitrate; - -public: - explicit PreparedVorbisEncoder(const ConfigBlock &block); - - /* virtual methods from class PreparedEncoder */ - Encoder *Open(AudioFormat &audio_format) override; - - [[nodiscard]] const char *GetMimeType() const noexcept override { - return "audio/ogg"; - } -}; - -PreparedVorbisEncoder::PreparedVorbisEncoder(const ConfigBlock &block) -{ - const char *value = block.GetBlockValue("quality"); - if (value != nullptr) { - /* a quality was configured (VBR) */ - - char *endptr; - quality = ParseDouble(value, &endptr); - - if (*endptr != '\0' || quality < -1.0f || quality > 10.0f) - throw FmtRuntimeError("quality {:?} is not a number in the " - "range -1 to 10", - value); - - if (block.GetBlockValue("bitrate") != nullptr) - throw std::runtime_error("quality and bitrate are both defined"); - } else { - /* a bit rate was configured */ - - value = block.GetBlockValue("bitrate"); - if (value == nullptr) - return; - - quality = -2.0; - - char *endptr; - bitrate = ParseInt(value, &endptr); - if (*endptr != '\0' || bitrate <= 0) - throw std::runtime_error("bitrate should be a positive integer"); - } -} - -static PreparedEncoder * -vorbis_encoder_init(const ConfigBlock &block) -{ - return new PreparedVorbisEncoder(block); -} - -VorbisEncoder::VorbisEncoder(float quality, int bitrate, - AudioFormat &_audio_format) - :OggEncoder(true) -{ - vorbis_info_init(&vi); - - _audio_format.format = SampleFormat::FLOAT; - audio_format = _audio_format; - - if (quality >= -1.0f) { - /* a quality was configured (VBR) */ - - if (0 != vorbis_encode_init_vbr(&vi, - audio_format.channels, - audio_format.sample_rate, - quality * 0.1f)) { - vorbis_info_clear(&vi); - throw std::runtime_error("error initializing vorbis vbr"); - } - } else { - /* a bit rate was configured */ - - if (0 != vorbis_encode_init(&vi, - audio_format.channels, - audio_format.sample_rate, -1.0, - bitrate * 1000, -1.0f)) { - vorbis_info_clear(&vi); - throw std::runtime_error("error initializing vorbis encoder"); - } - } - - vorbis_analysis_init(&vd, &vi); - vorbis_block_init(&vd, &vb); - - SendHeader(); -} - -void -VorbisEncoder::HeaderOut(vorbis_comment &vc) -{ - ogg_packet packet, comments, codebooks; - - vorbis_analysis_headerout(&vd, &vc, - &packet, &comments, &codebooks); - - stream.PacketIn(packet); - stream.PacketIn(comments); - stream.PacketIn(codebooks); -} - -void -VorbisEncoder::SendHeader() -{ - VorbisComment vc; - HeaderOut(vc); -} - -Encoder * -PreparedVorbisEncoder::Open(AudioFormat &audio_format) -{ - return new VorbisEncoder(quality, bitrate, audio_format); -} - -void -VorbisEncoder::BlockOut() -{ - while (vorbis_analysis_blockout(&vd, &vb) == 1) { - vorbis_analysis(&vb, nullptr); - vorbis_bitrate_addblock(&vb); - - ogg_packet packet; - while (vorbis_bitrate_flushpacket(&vd, &packet)) - stream.PacketIn(packet); - } -} - -void -VorbisEncoder::PreTag() -{ - vorbis_analysis_wrote(&vd, 0); - BlockOut(); - - /* reinitialize vorbis_dsp_state and vorbis_block to reset the - end-of-stream marker */ - vorbis_block_clear(&vb); - vorbis_dsp_clear(&vd); - vorbis_analysis_init(&vd, &vi); - vorbis_block_init(&vd, &vb); - - Flush(); -} - -static void -copy_tag_to_vorbis_comment(VorbisComment &vc, const Tag &tag) -{ - for (const auto &item : tag) { - char name[64]; - ToUpperASCII(name, tag_item_names[item.type], sizeof(name)); - vc.AddTag(name, item.value); - } -} - -void -VorbisEncoder::SendTag(const Tag &tag) -{ - /* write the vorbis_comment object */ - - VorbisComment comment; - copy_tag_to_vorbis_comment(comment, tag); - - /* reset ogg_stream_state and begin a new stream */ - - stream.Reinitialize(GenerateSerial()); - - /* send that vorbis_comment to the ogg_stream_state */ - - HeaderOut(comment); -} - -static void -interleaved_to_vorbis_buffer(float **dest, const float *src, - std::size_t num_frames, std::size_t num_channels) -{ - for (unsigned i = 0; i < num_frames; i++) - for (unsigned j = 0; j < num_channels; j++) - dest[j][i] = *src++; -} - -void -VorbisEncoder::Write(std::span src) -{ - std::size_t num_frames = src.size() / audio_format.GetFrameSize(); - - /* this is for only 16-bit audio */ - - interleaved_to_vorbis_buffer(vorbis_analysis_buffer(&vd, num_frames), - (const float *)(const void *)src.data(), - num_frames, - audio_format.channels); - - vorbis_analysis_wrote(&vd, num_frames); - BlockOut(); -} - -const EncoderPlugin vorbis_encoder_plugin = { - "vorbis", - vorbis_encoder_init, -}; diff --git a/src/encoder/plugins/VorbisEncoderPlugin.hxx b/src/encoder/plugins/VorbisEncoderPlugin.hxx deleted file mode 100644 index a95a0a1..0000000 --- a/src/encoder/plugins/VorbisEncoderPlugin.hxx +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#ifndef MPD_ENCODER_VORBIS_H -#define MPD_ENCODER_VORBIS_H - -extern const struct EncoderPlugin vorbis_encoder_plugin; - -#endif diff --git a/src/encoder/plugins/WaveEncoderPlugin.cxx b/src/encoder/plugins/WaveEncoderPlugin.cxx index 81661f5..56bc43d 100644 --- a/src/encoder/plugins/WaveEncoderPlugin.cxx +++ b/src/encoder/plugins/WaveEncoderPlugin.cxx @@ -1,217 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Copyright The Music Player Daemon Project +// STUB FILE - Encoder support removed for mpd-dbcreate #include "WaveEncoderPlugin.hxx" -#include "../EncoderAPI.hxx" -#include "tag/RiffFormat.hxx" -#include "util/ByteOrder.hxx" -#include "util/DynamicFifoBuffer.hxx" - -#include - -#include - -class WaveEncoder final : public Encoder { - unsigned bits; - - DynamicFifoBuffer buffer{8192}; - -public: - explicit WaveEncoder(AudioFormat &audio_format) noexcept; - - /* virtual methods from class Encoder */ - void Write(std::span src) override; - - std::span Read(std::span b) noexcept override { - return b.first(buffer.Read(b.data(), b.size())); - } -}; - -class PreparedWaveEncoder final : public PreparedEncoder { - /* virtual methods from class PreparedEncoder */ - Encoder *Open(AudioFormat &audio_format) override { - return new WaveEncoder(audio_format); - } - - [[nodiscard]] const char *GetMimeType() const noexcept override { - return "audio/wav"; - } -}; - -struct WaveHeader { - RiffFileHeader file_header; - RiffChunkHeader fmt_header; - RiffFmtChunk fmt; - RiffChunkHeader data_header; -}; - -static_assert(sizeof(WaveHeader) == 44); - -static WaveHeader -MakeWaveHeader(int channels, int bits, - int freq, int block_size) noexcept -{ - WaveHeader header{}; - - int data_size = 0x0FFFFFFF; - - /* constants */ - memcpy(header.file_header.id, "RIFF", 4); - memcpy(header.file_header.format, "WAVE", 4); - memcpy(header.fmt_header.id, "fmt ", 4); - memcpy(header.data_header.id, "data", 4); - - /* wave format */ - header.fmt.tag = ToLE16(RiffFmtChunk::TAG_PCM); - header.fmt.channels = ToLE16(channels); - header.fmt.bits_per_sample = ToLE16(bits); - header.fmt.sample_rate = ToLE32(freq); - header.fmt.block_align = ToLE16(block_size); - header.fmt.byte_rate = ToLE32(freq * block_size); - - /* chunk sizes (fake data length) */ - header.fmt_header.size = ToLE32(sizeof(header.fmt)); - header.data_header.size = ToLE32(data_size); - header.file_header.size = ToLE32(4 + - sizeof(header.fmt_header) + sizeof(header.fmt) + - sizeof(header.data_header) + data_size); - - return header; -} - -static PreparedEncoder * -wave_encoder_init([[maybe_unused]] const ConfigBlock &block) -{ - return new PreparedWaveEncoder(); -} - -WaveEncoder::WaveEncoder(AudioFormat &audio_format) noexcept - :Encoder(false) -{ - assert(audio_format.IsValid()); - - switch (audio_format.format) { - case SampleFormat::S8: - bits = 8; - break; - - case SampleFormat::S16: - bits = 16; - break; - - case SampleFormat::S24_P32: - bits = 24; - break; - - case SampleFormat::S32: - bits = 32; - break; - - default: - audio_format.format = SampleFormat::S16; - bits = 16; - break; - } - - auto range = buffer.Write(); - assert(range.size() >= sizeof(WaveHeader)); - auto *header = (WaveHeader *)(void *)range.data(); - - /* create PCM wave header in initial buffer */ - *header = MakeWaveHeader(audio_format.channels, - bits, - audio_format.sample_rate, - (bits / 8) * audio_format.channels); - - buffer.Append(sizeof(*header)); -} - -static size_t -pcm16_to_wave(uint16_t *dst16, const uint16_t *src16, size_t length) -{ - size_t cnt = length >> 1; - while (cnt > 0) { - *dst16++ = ToLE16(*src16++); - cnt--; - } - return length; -} - -static size_t -pcm32_to_wave(uint32_t *dst32, const uint32_t *src32, size_t length) noexcept -{ - size_t cnt = length >> 2; - while (cnt > 0){ - *dst32++ = ToLE32(*src32++); - cnt--; - } - return length; -} - -static size_t -pcm24_to_wave(uint8_t *dst8, const uint32_t *src32, size_t length) noexcept -{ - uint32_t value; - uint8_t *dst_old = dst8; - - length = length >> 2; - while (length > 0){ - value = *src32++; - *dst8++ = (value) & 0xFF; - *dst8++ = (value >> 8) & 0xFF; - *dst8++ = (value >> 16) & 0xFF; - length--; - } - //correct buffer length - return (dst8 - dst_old); -} - -void -WaveEncoder::Write(std::span src) -{ - std::size_t length = src.size(); - std::byte *dst = buffer.Write(length); - - if (IsLittleEndian()) { - switch (bits) { - case 8: - case 16: - case 32:// optimized cases - memcpy(dst, src.data(), length); - break; - case 24: - length = pcm24_to_wave((uint8_t *)dst, - (const uint32_t *)(const void *)src.data(), - length); - break; - } - } else { - switch (bits) { - case 8: - memcpy(dst, src.data(), length); - break; - case 16: - length = pcm16_to_wave((uint16_t *)dst, - (const uint16_t *)(const void *)src.data(), - length); - break; - case 24: - length = pcm24_to_wave((uint8_t *)dst, - (const uint32_t *)(const void *)src.data(), - length); - break; - case 32: - length = pcm32_to_wave((uint32_t *)dst, - (const uint32_t *)(const void *)src.data(), - length); - break; - } - } - - buffer.Append(length); -} +/** + * Stub implementation - encoder support not needed for database creation + */ const EncoderPlugin wave_encoder_plugin = { "wave", - wave_encoder_init, }; diff --git a/src/encoder/plugins/WaveEncoderPlugin.hxx b/src/encoder/plugins/WaveEncoderPlugin.hxx index 5720bf9..f5c205e 100644 --- a/src/encoder/plugins/WaveEncoderPlugin.hxx +++ b/src/encoder/plugins/WaveEncoderPlugin.hxx @@ -1,9 +1,15 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Copyright The Music Player Daemon Project +// STUB FILE - Encoder support removed for mpd-dbcreate -#ifndef MPD_ENCODER_WAVE_HXX -#define MPD_ENCODER_WAVE_HXX +#ifndef MPD_WAVE_ENCODER_PLUGIN_HXX +#define MPD_WAVE_ENCODER_PLUGIN_HXX -extern const struct EncoderPlugin wave_encoder_plugin; +#include "encoder/EncoderPlugin.hxx" + +/** + * Stub implementation - encoder support not needed for database creation + */ +extern const EncoderPlugin wave_encoder_plugin; #endif diff --git a/src/encoder/plugins/meson.build b/src/encoder/plugins/meson.build deleted file mode 100644 index b0c4aed..0000000 --- a/src/encoder/plugins/meson.build +++ /dev/null @@ -1,80 +0,0 @@ -encoder_plugins_sources = [ - 'NullEncoderPlugin.cxx', -] - -encoder_features.set('ENABLE_FLAC_ENCODER', flac_dep.found()) -if flac_dep.found() - encoder_plugins_sources += 'FlacEncoderPlugin.cxx' -endif - -if libopus_dep.found() - encoder_plugins_sources += 'OpusEncoderPlugin.cxx' -endif - -encoder_features.set('ENABLE_VORBISENC', libvorbisenc_dep.found()) -if libvorbisenc_dep.found() - encoder_plugins_sources += 'VorbisEncoderPlugin.cxx' -endif - -if not get_option('lame').disabled() - # LAME doesn't have a pkg-config file so we have to use - # find_library() - liblame_dep = c_compiler.find_library('mp3lame', required: false) - if not liblame_dep.found() - # only if that was not found, use dependency() which may use the - # LAME subproject - liblame_dep = dependency('mp3lame', required: get_option('lame')) - endif -else - liblame_dep = dependency('', required: false) -endif - -encoder_features.set('ENABLE_LAME', liblame_dep.found()) -if liblame_dep.found() - encoder_plugins_sources += 'LameEncoderPlugin.cxx' -endif - -libtwolame_dep = dependency('twolame', required: get_option('twolame')) -encoder_features.set('ENABLE_TWOLAME', libtwolame_dep.found()) -if libtwolame_dep.found() - encoder_plugins_sources += 'TwolameEncoderPlugin.cxx' -endif - -libshine_dep = dependency('shine', version: '>= 3.1', required: get_option('shine')) -encoder_features.set('ENABLE_SHINE', libshine_dep.found()) -if libshine_dep.found() - encoder_plugins_sources += 'ShineEncoderPlugin.cxx' -endif - -encoder_features.set('ENABLE_WAVE_ENCODER', get_option('wave_encoder')) -if get_option('wave_encoder') or need_wave_encoder - encoder_plugins_sources += 'WaveEncoderPlugin.cxx' -endif - -encoder_plugins = static_library( - 'encoder_plugins', - encoder_plugins_sources, - include_directories: inc, - dependencies: [ - pcm_basic_dep, - flac_dep, - ogg_dep, - libopus_dep, - libvorbisenc_dep, - libvorbis_dep, - liblame_dep, - libtwolame_dep, - libshine_dep, - log_dep, - ], -) - -encoder_plugins_dep = declare_dependency( - link_with: encoder_plugins, - dependencies: [ - encoder_api_dep, - tag_dep, - pcm_dep, - config_dep, - ], -) diff --git a/src/filter/Factory.cxx b/src/filter/Factory.cxx deleted file mode 100644 index 2571cc9..0000000 --- a/src/filter/Factory.cxx +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#include "Factory.hxx" -#include "LoadOne.hxx" -#include "Prepared.hxx" -#include "config/Data.hxx" -#include "config/Block.hxx" -#include "lib/fmt/RuntimeError.hxx" - -std::unique_ptr -FilterFactory::MakeFilter(const char *name) -{ - const auto *cfg = config.FindBlock(ConfigBlockOption::AUDIO_FILTER, - "name", name); - if (cfg == nullptr) - throw FmtRuntimeError("Filter template not found: {}", - name); - - cfg->SetUsed(); - - return filter_configured_new(*cfg); -} diff --git a/src/filter/Factory.hxx b/src/filter/Factory.hxx index 6ad9f38..2a1a92f 100644 --- a/src/filter/Factory.hxx +++ b/src/filter/Factory.hxx @@ -1,22 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Copyright The Music Player Daemon Project +// STUB FILE - Filter support removed for mpd-dbcreate #ifndef MPD_FILTER_FACTORY_HXX #define MPD_FILTER_FACTORY_HXX -#include - struct ConfigData; -class PreparedFilter; +/** + * Stub implementation - filter support not needed for database creation + */ class FilterFactory { - const ConfigData &config; - public: - explicit FilterFactory(const ConfigData &_config) noexcept - :config(_config) {} - - std::unique_ptr MakeFilter(const char *name); + FilterFactory([[maybe_unused]] const ConfigData &config) {} }; #endif diff --git a/src/filter/Filter.cxx b/src/filter/Filter.cxx new file mode 100644 index 0000000..5358222 --- /dev/null +++ b/src/filter/Filter.cxx @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright The Music Player Daemon Project +// STUB FILE - Filter support removed for mpd-dbcreate + +#include "Filter.hxx" +#include "pcm/AudioFormat.hxx" + +const AudioFormat & +Filter::GetOutAudioFormat() const noexcept +{ + // Return a static dummy audio format with minimal valid initialization + static const AudioFormat dummy_format{44100, SampleFormat::S16, 2}; + return dummy_format; +} diff --git a/src/filter/Filter.hxx b/src/filter/Filter.hxx index 4087aeb..6d2c5d7 100644 --- a/src/filter/Filter.hxx +++ b/src/filter/Filter.hxx @@ -1,84 +1,42 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Copyright The Music Player Daemon Project +// STUB FILE - Filter support removed for mpd-dbcreate #ifndef MPD_FILTER_HXX #define MPD_FILTER_HXX -#include "pcm/AudioFormat.hxx" - -#include -#include #include +#include +#include -class Filter { -protected: - AudioFormat out_audio_format; - - explicit Filter(AudioFormat _out_audio_format) noexcept - :out_audio_format(_out_audio_format) { - assert(out_audio_format.IsValid()); - } +struct AudioFormat; +/** + * Stub implementation - filter support not needed for database creation + */ +class Filter { public: - virtual ~Filter() noexcept = default; + virtual ~Filter() = default; - /** - * Returns the #AudioFormat produced by FilterPCM(). - */ - const AudioFormat &GetOutAudioFormat() const noexcept { - return out_audio_format; + virtual std::span FilterPCM(std::span src) { + return src; // Pass-through stub } - /** - * Reset the filter's state, e.g. drop/flush buffers. - */ - virtual void Reset() noexcept { + virtual std::span Flush() { + return {}; // Empty stub } - /** - * Filters a block of PCM data. - * - * Throws on error. - * - * @param src the input buffer - * @return the output buffer (will be invalidated by deleting - * this object or any call to Reset(), FilterPCM(), ReadMore() - * or Flush()); may be empty if no output is currently - * available - */ - virtual std::span FilterPCM(std::span src) = 0; - - /** - * Read more result data from the filter. After each - * FilterPCM() call, this should be called repeatedly until it - * returns an empty span. - * - * Throws on error. - * - * @return the output buffer (will be invalidated by deleting - * this object or any call to Reset(), FilterPCM(), ReadMore() - * or Flush()); may be empty if no output is currently - * available - */ virtual std::span ReadMore() { - return {}; + return {}; // Empty stub } - /** - * Flush pending data and return it. This should be called - * repeatedly until it returns an empty span. - * - * After calling this method, this object cannot be used again - * (not even Reset() is allowed). - * - * Throws on error. - * - * @return pending data (will be invalidated by deleting this - * object or by any call to Flush()) - */ - virtual std::span Flush() { - return {}; + virtual void Reset() noexcept { + // No-op stub } + + virtual const AudioFormat &GetOutAudioFormat() const noexcept; }; +class PreparedFilter; // Forward declaration - see Prepared.hxx for full definition + #endif diff --git a/src/filter/FilterPlugin.hxx b/src/filter/FilterPlugin.hxx deleted file mode 100644 index 81592b2..0000000 --- a/src/filter/FilterPlugin.hxx +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -/** \file - * - * This header declares the filter_plugin class. It describes a - * plugin API for objects which filter raw PCM data. - */ - -#ifndef MPD_FILTER_PLUGIN_HXX -#define MPD_FILTER_PLUGIN_HXX - -#include - -struct ConfigBlock; -class PreparedFilter; - -struct FilterPlugin { - const char *name; - - /** - * Allocates and configures a filter. - */ - std::unique_ptr (*init)(const ConfigBlock &block); -}; - -#endif diff --git a/src/filter/LoadChain.cxx b/src/filter/LoadChain.cxx deleted file mode 100644 index 2d34e66..0000000 --- a/src/filter/LoadChain.cxx +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#include "LoadChain.hxx" -#include "Factory.hxx" -#include "Prepared.hxx" -#include "plugins/AutoConvertFilterPlugin.hxx" -#include "plugins/TwoFilters.hxx" -#include "util/IterableSplitString.hxx" - -#include - -static void -filter_chain_append_new(std::unique_ptr &chain, - FilterFactory &factory, - std::string_view template_name) -{ - /* using the AutoConvert filter just in case the specified - filter plugin does not support the exact input format */ - - chain = ChainFilters(std::move(chain), - /* unfortunately, MakeFilter() wants a - null-terminated string, so we need to - copy it here */ - autoconvert_filter_new(factory.MakeFilter(std::string(template_name).c_str())), - template_name); -} - -void -filter_chain_parse(std::unique_ptr &chain, - FilterFactory &factory, - const char *spec) -{ - for (const std::string_view i : IterableSplitString(spec, ',')) { - if (i.empty()) - continue; - - filter_chain_append_new(chain, factory, i); - } -} diff --git a/src/filter/LoadChain.hxx b/src/filter/LoadChain.hxx index 7deb76d..524eedf 100644 --- a/src/filter/LoadChain.hxx +++ b/src/filter/LoadChain.hxx @@ -1,28 +1,31 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Copyright The Music Player Daemon Project +// STUB FILE - Filter support removed for mpd-dbcreate #ifndef MPD_FILTER_LOAD_CHAIN_HXX #define MPD_FILTER_LOAD_CHAIN_HXX +#include "Prepared.hxx" #include class FilterFactory; -class PreparedFilter; +struct ConfigBlock; /** - * Builds a filter chain from a configuration string on the form - * "name1, name2, name3, ..." by looking up each name among the - * configured filter sections. - * - * Throws on error. - * - * @param chain the chain to append filters on - * @param config the global configuration to load filter definitions from - * @param spec the filter chain specification + * Stub implementation - filter support not needed for database creation */ -void -filter_chain_parse(std::unique_ptr &chain, - FilterFactory &factory, - const char *spec); +inline std::unique_ptr +filter_chain_parse([[maybe_unused]] std::unique_ptr &prepared, + [[maybe_unused]] FilterFactory &factory, + [[maybe_unused]] const char *spec) +{ + return nullptr; +} + +inline std::unique_ptr +filter_chain_new([[maybe_unused]] const ConfigBlock *block) +{ + return nullptr; +} #endif diff --git a/src/filter/LoadOne.cxx b/src/filter/LoadOne.cxx deleted file mode 100644 index 637e892..0000000 --- a/src/filter/LoadOne.cxx +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#include "LoadOne.hxx" -#include "FilterPlugin.hxx" -#include "Registry.hxx" -#include "Prepared.hxx" -#include "config/Block.hxx" -#include "lib/fmt/RuntimeError.hxx" - -std::unique_ptr -filter_configured_new(const ConfigBlock &block) -{ - const char *plugin_name = block.GetBlockValue("plugin"); - if (plugin_name == nullptr) - throw std::runtime_error("No filter plugin specified"); - - const auto *plugin = filter_plugin_by_name(plugin_name); - if (plugin == nullptr) - throw FmtRuntimeError("No such filter plugin: {}", - plugin_name); - - return plugin->init(block); -} diff --git a/src/filter/LoadOne.hxx b/src/filter/LoadOne.hxx deleted file mode 100644 index 91728c2..0000000 --- a/src/filter/LoadOne.hxx +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#ifndef MPD_FILTER_LOAD_ONE_HXX -#define MPD_FILTER_LOAD_ONE_HXX - -#include - -struct ConfigBlock; -class PreparedFilter; - -/** - * Creates a new filter, loads configuration and the plugin name from - * the specified configuration section. - * - * Throws on error. - * - * @param block the configuration section - */ -std::unique_ptr -filter_configured_new(const ConfigBlock &block); - -#endif diff --git a/src/filter/NullFilter.hxx b/src/filter/NullFilter.hxx deleted file mode 100644 index 5e2d8a6..0000000 --- a/src/filter/NullFilter.hxx +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#ifndef MPD_NULL_FILTER_HXX -#define MPD_NULL_FILTER_HXX - -#include "filter/Filter.hxx" - -class NullFilter final : public Filter { -public: - explicit NullFilter(const AudioFormat &af):Filter(af) {} - - std::span FilterPCM(std::span src) override { - return src; - } -}; - -#endif diff --git a/src/filter/Observer.cxx b/src/filter/Observer.cxx deleted file mode 100644 index 213be77..0000000 --- a/src/filter/Observer.cxx +++ /dev/null @@ -1,114 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#include "Observer.hxx" -#include "Filter.hxx" -#include "Prepared.hxx" - -#include - -class FilterObserver::PreparedProxy final : public PreparedFilter { - FilterObserver &observer; - - std::unique_ptr prepared_filter; - Proxy *child = nullptr; - -public: - PreparedProxy(FilterObserver &_observer, - std::unique_ptr _prepared_filter) noexcept - :observer(_observer), - prepared_filter(std::move(_prepared_filter)) {} - - ~PreparedProxy() noexcept override { - assert(child == nullptr); - assert(observer.proxy == this); - - observer.proxy = nullptr; - } - - PreparedProxy(const PreparedProxy &) = delete; - PreparedProxy &operator=(const PreparedProxy &) = delete; - - void Clear([[maybe_unused]] Proxy *_child) noexcept { - assert(child == _child); - child = nullptr; - } - - Filter *Get() noexcept; - - std::unique_ptr Open(AudioFormat &af) override; -}; - -class FilterObserver::Proxy final : public Filter { - PreparedProxy &parent; - - std::unique_ptr filter; - -public: - Proxy(PreparedProxy &_parent, std::unique_ptr _filter) noexcept - :Filter(_filter->GetOutAudioFormat()), - parent(_parent), filter(std::move(_filter)) {} - - ~Proxy() noexcept override { - parent.Clear(this); - } - - Proxy(const Proxy &) = delete; - Proxy &operator=(const Proxy &) = delete; - - Filter *Get() noexcept { - return filter.get(); - } - - void Reset() noexcept override { - filter->Reset(); - } - - std::span FilterPCM(std::span src) override { - return filter->FilterPCM(src); - } - - std::span ReadMore() override { - return filter->ReadMore(); - } - - std::span Flush() override { - return filter->Flush(); - } -}; - -Filter * -FilterObserver::PreparedProxy::Get() noexcept -{ - return child != nullptr - ? child->Get() - : nullptr; -} - -std::unique_ptr -FilterObserver::PreparedProxy::Open(AudioFormat &af) -{ - assert(child == nullptr); - - auto c = std::make_unique(*this, prepared_filter->Open(af)); - child = c.get(); - return c; -} - -std::unique_ptr -FilterObserver::Set(std::unique_ptr pf) -{ - assert(proxy == nullptr); - - auto p = std::make_unique(*this, std::move(pf)); - proxy = p.get(); - return p; -} - -Filter * -FilterObserver::Get() noexcept -{ - return proxy != nullptr - ? proxy->Get() - : nullptr; -} diff --git a/src/filter/Observer.hxx b/src/filter/Observer.hxx index d5f00bf..5c5b2f5 100644 --- a/src/filter/Observer.hxx +++ b/src/filter/Observer.hxx @@ -1,31 +1,32 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Copyright The Music Player Daemon Project +// STUB FILE - Filter support removed for mpd-dbcreate #ifndef MPD_FILTER_OBSERVER_HXX #define MPD_FILTER_OBSERVER_HXX #include -class PreparedFilter; class Filter; +class PreparedFilter; /** - * A helper class which observes calls to a #PreparedFilter and allows - * the caller to access the #Filter instances created by it. + * Stub implementation - filter support not needed for database creation */ class FilterObserver { - class PreparedProxy; - class Proxy; +public: + FilterObserver() noexcept = default; - PreparedProxy *proxy = nullptr; + Filter *Get() noexcept { return nullptr; } -public: - /** - * @return a proxy object - */ - std::unique_ptr Set(std::unique_ptr pf); + void Set(Filter *) noexcept {} - Filter *Get() noexcept; + // Also accept PreparedFilter unique_ptr, return it for chaining + // Use template to avoid incomplete type issues + template + std::unique_ptr Set(std::unique_ptr p) noexcept { + return p; + } }; #endif diff --git a/src/filter/Prepared.hxx b/src/filter/Prepared.hxx index 93322b3..2685b05 100644 --- a/src/filter/Prepared.hxx +++ b/src/filter/Prepared.hxx @@ -1,28 +1,25 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Copyright The Music Player Daemon Project +// STUB FILE - Filter support removed for mpd-dbcreate -#ifndef MPD_PREPARED_FILTER_HXX -#define MPD_PREPARED_FILTER_HXX +#ifndef MPD_FILTER_PREPARED_HXX +#define MPD_FILTER_PREPARED_HXX +#include "Filter.hxx" #include struct AudioFormat; -class Filter; +/** + * Stub implementation - filter support not needed for database creation + */ class PreparedFilter { public: virtual ~PreparedFilter() = default; - /** - * Opens the filter, preparing it for FilterPCM(). - * - * Throws on error. - * - * @param af the audio format of incoming data; the - * plugin may modify the object to enforce another input - * format - */ - virtual std::unique_ptr Open(AudioFormat &af) = 0; + virtual std::unique_ptr Open([[maybe_unused]] const AudioFormat &af) { + return nullptr; // Stub returns nullptr + } }; #endif diff --git a/src/filter/Registry.cxx b/src/filter/Registry.cxx deleted file mode 100644 index c4c285e..0000000 --- a/src/filter/Registry.cxx +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#include "Registry.hxx" -#include "FilterPlugin.hxx" -#include "plugins/NullFilterPlugin.hxx" -#include "plugins/RouteFilterPlugin.hxx" -#include "plugins/NormalizeFilterPlugin.hxx" -#include "plugins/FfmpegFilterPlugin.hxx" -#include "plugins/HdcdFilterPlugin.hxx" -#include "config.h" - -#include - -static constinit const FilterPlugin *const filter_plugins[] = { - &null_filter_plugin, - &route_filter_plugin, - &normalize_filter_plugin, -#ifdef HAVE_LIBAVFILTER - &ffmpeg_filter_plugin, - &hdcd_filter_plugin, -#endif - nullptr, -}; - -const FilterPlugin * -filter_plugin_by_name(const char *name) noexcept -{ - for (unsigned i = 0; filter_plugins[i] != nullptr; ++i) - if (strcmp(filter_plugins[i]->name, name) == 0) - return filter_plugins[i]; - - return nullptr; -} diff --git a/src/filter/Registry.hxx b/src/filter/Registry.hxx deleted file mode 100644 index 5572fb3..0000000 --- a/src/filter/Registry.hxx +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -/** \file - * - * This library manages all filter plugins which are enabled at - * compile time. - */ - -#ifndef MPD_FILTER_REGISTRY_HXX -#define MPD_FILTER_REGISTRY_HXX - -struct FilterPlugin; - -[[gnu::pure]] -const FilterPlugin * -filter_plugin_by_name(const char *name) noexcept; - -#endif diff --git a/src/filter/meson.build b/src/filter/meson.build index 4e1123a..bdc0769 100644 --- a/src/filter/meson.build +++ b/src/filter/meson.build @@ -1,6 +1,9 @@ +# STUB FILE - Filter support removed for mpd-dbcreate +# Minimal build file for stub implementations + filter_api = static_library( 'filter_api', - 'Observer.cxx', + 'Filter.cxx', include_directories: inc, ) @@ -8,23 +11,12 @@ filter_api_dep = declare_dependency( link_with: filter_api, ) -subdir('plugins') - -filter_glue = static_library( - 'filter_glue', - 'Registry.cxx', - 'Factory.cxx', - 'LoadOne.cxx', - 'LoadChain.cxx', - include_directories: inc, - dependencies: [ - fmt_dep, - ], -) +# Empty stub library for plugin dependencies +filter_plugins_dep = declare_dependency() +# Empty stub library for filter glue dependencies filter_glue_dep = declare_dependency( - link_with: filter_glue, dependencies: [ - filter_plugins_dep, + filter_api_dep, ], ) diff --git a/src/filter/plugins/AutoConvertFilterPlugin.cxx b/src/filter/plugins/AutoConvertFilterPlugin.cxx deleted file mode 100644 index 609084c..0000000 --- a/src/filter/plugins/AutoConvertFilterPlugin.cxx +++ /dev/null @@ -1,56 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#include "AutoConvertFilterPlugin.hxx" -#include "ConvertFilterPlugin.hxx" -#include "TwoFilters.hxx" -#include "filter/Filter.hxx" -#include "filter/Prepared.hxx" -#include "pcm/AudioFormat.hxx" - -#include -#include - -class PreparedAutoConvertFilter final : public PreparedFilter { - /** - * The underlying filter. - */ - std::unique_ptr filter; - -public: - explicit PreparedAutoConvertFilter(std::unique_ptr _filter) noexcept - :filter(std::move(_filter)) {} - - std::unique_ptr Open(AudioFormat &af) override; -}; - -std::unique_ptr -PreparedAutoConvertFilter::Open(AudioFormat &in_audio_format) -{ - assert(in_audio_format.IsValid()); - - /* open the "real" filter */ - - AudioFormat child_audio_format = in_audio_format; - auto new_filter = filter->Open(child_audio_format); - - /* need to convert? */ - - if (in_audio_format == child_audio_format) - /* no */ - return new_filter; - - /* yes - create a convert_filter */ - - auto convert = convert_filter_new(in_audio_format, - child_audio_format); - - return std::make_unique(std::move(convert), - std::move(new_filter)); -} - -std::unique_ptr -autoconvert_filter_new(std::unique_ptr filter) noexcept -{ - return std::make_unique(std::move(filter)); -} diff --git a/src/filter/plugins/AutoConvertFilterPlugin.hxx b/src/filter/plugins/AutoConvertFilterPlugin.hxx index 0107a3b..819713f 100644 --- a/src/filter/plugins/AutoConvertFilterPlugin.hxx +++ b/src/filter/plugins/AutoConvertFilterPlugin.hxx @@ -1,20 +1,20 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Copyright The Music Player Daemon Project +// STUB FILE - Filter support removed for mpd-dbcreate -#ifndef MPD_AUTOCONVERT_FILTER_PLUGIN_HXX -#define MPD_AUTOCONVERT_FILTER_PLUGIN_HXX +#ifndef MPD_AUTO_CONVERT_FILTER_PLUGIN_HXX +#define MPD_AUTO_CONVERT_FILTER_PLUGIN_HXX +#include "filter/Prepared.hxx" #include -class PreparedFilter; - /** - * Creates a new "autoconvert" filter. When opened, it ensures that - * the input audio format isn't changed. If the underlying filter - * requests a different format, it automatically creates a - * convert_filter. + * Stub implementation - filter support not needed for database creation */ -std::unique_ptr -autoconvert_filter_new(std::unique_ptr filter) noexcept; +inline std::unique_ptr +autoconvert_filter_new([[maybe_unused]] std::unique_ptr a = nullptr) +{ + return nullptr; +} #endif diff --git a/src/filter/plugins/ConvertFilterPlugin.cxx b/src/filter/plugins/ConvertFilterPlugin.cxx deleted file mode 100644 index 8d07184..0000000 --- a/src/filter/plugins/ConvertFilterPlugin.cxx +++ /dev/null @@ -1,118 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#include "ConvertFilterPlugin.hxx" -#include "filter/Filter.hxx" -#include "filter/Prepared.hxx" -#include "pcm/AudioFormat.hxx" -#include "pcm/Convert.hxx" - -#include -#include - -class ConvertFilter final : public Filter { - /** - * The input audio format; PCM data is passed to the filter() - * method in this format. - */ - const AudioFormat in_audio_format; - - /** - * This object is only "open" if #in_audio_format != - * #out_audio_format. - */ - std::unique_ptr state; - -public: - explicit ConvertFilter(const AudioFormat &audio_format); - - void Set(const AudioFormat &_out_audio_format); - - void Reset() noexcept override { - if (state) - state->Reset(); - } - - std::span FilterPCM(std::span src) override; - - std::span Flush() override { - return state - ? state->Flush() - : std::span{}; - } -}; - -class PreparedConvertFilter final : public PreparedFilter { -public: - std::unique_ptr Open(AudioFormat &af) override; -}; - -void -ConvertFilter::Set(const AudioFormat &_out_audio_format) -{ - assert(_out_audio_format.IsValid()); - - if (_out_audio_format == out_audio_format) - /* no change */ - return; - - if (state) { - out_audio_format = in_audio_format; - state.reset(); - } - - if (_out_audio_format == in_audio_format) - /* optimized special case: no-op */ - return; - - state = std::make_unique(in_audio_format, - _out_audio_format); - - out_audio_format = _out_audio_format; -} - -ConvertFilter::ConvertFilter(const AudioFormat &audio_format) - :Filter(audio_format), in_audio_format(audio_format) -{ - assert(in_audio_format.IsValid()); -} - -std::unique_ptr -PreparedConvertFilter::Open(AudioFormat &audio_format) -{ - assert(audio_format.IsValid()); - - return std::make_unique(audio_format); -} - -std::span -ConvertFilter::FilterPCM(std::span src) -{ - return state - ? state->Convert(src) - /* optimized special case: no-op */ - : std::span{src}; -} - -std::unique_ptr -convert_filter_prepare() noexcept -{ - return std::make_unique(); -} - -std::unique_ptr -convert_filter_new(const AudioFormat in_audio_format, - const AudioFormat out_audio_format) -{ - auto filter = std::make_unique(in_audio_format); - filter->Set(out_audio_format); - return filter; -} - -void -convert_filter_set(Filter *_filter, AudioFormat out_audio_format) -{ - auto *filter = (ConvertFilter *)_filter; - - filter->Set(out_audio_format); -} diff --git a/src/filter/plugins/ConvertFilterPlugin.hxx b/src/filter/plugins/ConvertFilterPlugin.hxx index 78cfd5b..de90858 100644 --- a/src/filter/plugins/ConvertFilterPlugin.hxx +++ b/src/filter/plugins/ConvertFilterPlugin.hxx @@ -1,31 +1,37 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Copyright The Music Player Daemon Project +// STUB FILE - Filter support removed for mpd-dbcreate #ifndef MPD_CONVERT_FILTER_PLUGIN_HXX #define MPD_CONVERT_FILTER_PLUGIN_HXX +#include "filter/Prepared.hxx" #include -class PreparedFilter; -class Filter; struct AudioFormat; - -std::unique_ptr -convert_filter_prepare() noexcept; - -std::unique_ptr -convert_filter_new(AudioFormat in_audio_format, - AudioFormat out_audio_format); +class Filter; /** - * Sets the output audio format for the specified filter. You must - * call this after the filter has been opened. Since this audio - * format switch is a violation of the filter API, this filter must be - * the last in a chain. - * - * Throws on error. + * Stub implementation - filter support not needed for database creation */ -void -convert_filter_set(Filter *filter, AudioFormat out_audio_format); +inline std::unique_ptr +convert_filter_new([[maybe_unused]] const AudioFormat &in, + [[maybe_unused]] const AudioFormat &out) +{ + return nullptr; +} + +inline void +convert_filter_set([[maybe_unused]] Filter *, + [[maybe_unused]] const AudioFormat &) noexcept +{ + // No-op stub +} + +inline std::unique_ptr +convert_filter_prepare() +{ + return nullptr; +} #endif diff --git a/src/filter/plugins/FfmpegFilter.cxx b/src/filter/plugins/FfmpegFilter.cxx deleted file mode 100644 index 29bf7ad..0000000 --- a/src/filter/plugins/FfmpegFilter.cxx +++ /dev/null @@ -1,104 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#include "FfmpegFilter.hxx" -#include "lib/ffmpeg/Interleave.hxx" -#include "lib/ffmpeg/SampleFormat.hxx" - -extern "C" { -#include -#include -} - -#include - -FfmpegFilter::FfmpegFilter(const AudioFormat &in_audio_format, - const AudioFormat &_out_audio_format, - Ffmpeg::FilterGraph &&_graph, - AVFilterContext &_buffer_src, - AVFilterContext &_buffer_sink) noexcept - :Filter(_out_audio_format), - graph(std::move(_graph)), - buffer_src(_buffer_src), - buffer_sink(_buffer_sink), - in_format(Ffmpeg::ToFfmpegSampleFormat(in_audio_format.format)), - in_sample_rate(in_audio_format.sample_rate), -#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 25, 100) - in_channels(in_audio_format.channels), -#endif - in_audio_frame_size(in_audio_format.GetFrameSize()), - out_audio_frame_size(_out_audio_format.GetFrameSize()) -{ -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 25, 100) - av_channel_layout_default(&in_ch_layout, in_audio_format.channels); -#endif -} - -inline std::span -FfmpegFilter::ReadOutput() -{ - frame.Unref(); - - if (int err = av_buffersink_get_frame(&buffer_sink, frame.get()); err < 0) { - if (err == AVERROR(EAGAIN) || err == AVERROR_EOF) - return {}; - - throw MakeFfmpegError(err, "av_buffersink_get_frame() failed"); - } - - return Ffmpeg::InterleaveFrame(*frame, interleave_buffer); -} - -std::span -FfmpegFilter::FilterPCM(std::span src) -{ - assert(!flushed); - - /* submit source data into the FFmpeg audio buffer source */ - - frame.Unref(); - frame->format = in_format; - frame->sample_rate = in_sample_rate; -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 25, 100) - frame->ch_layout = in_ch_layout; -#else - frame->channels = in_channels; -#endif - frame->nb_samples = src.size() / in_audio_frame_size; - - frame->pts = pts; - pts += frame->nb_samples; - - frame.GetBuffer(); - - memcpy(frame.GetData(0), src.data(), src.size()); - - if (int err = av_buffersrc_add_frame(&buffer_src, frame.get()); err < 0) - throw MakeFfmpegError(err, "av_buffersrc_write_frame() failed"); - - /* collect filtered data from the FFmpeg audio buffer sink */ - - /* TODO: call av_buffersink_get_frame() repeatedly? Not - possible with MPD's current Filter API */ - - return ReadOutput(); -} - -std::span -FfmpegFilter::ReadMore() -{ - return ReadOutput(); -} - -std::span -FfmpegFilter::Flush() -{ - if (!flushed) { - if (int err = av_buffersrc_add_frame(&buffer_src, nullptr); err < 0) - throw MakeFfmpegError(err, "av_buffersrc_write_frame() failed"); - - flushed = true; - } - - return ReadOutput(); -} diff --git a/src/filter/plugins/FfmpegFilter.hxx b/src/filter/plugins/FfmpegFilter.hxx deleted file mode 100644 index a22b560..0000000 --- a/src/filter/plugins/FfmpegFilter.hxx +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#pragma once - -#include "filter/Filter.hxx" -#include "lib/ffmpeg/Buffer.hxx" -#include "lib/ffmpeg/Filter.hxx" -#include "lib/ffmpeg/Frame.hxx" - -#include - -/** - * A #Filter implementation using FFmpeg's libavfilter. - */ -class FfmpegFilter final : public Filter { - Ffmpeg::FilterGraph graph; - AVFilterContext &buffer_src, &buffer_sink; - Ffmpeg::Frame frame; - - FfmpegBuffer interleave_buffer; - - const int in_format, in_sample_rate; - -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 25, 100) - AVChannelLayout in_ch_layout; -#else - const int in_channels; -#endif - - const size_t in_audio_frame_size; - const size_t out_audio_frame_size; - - /** - * Presentation timestamp. A counter for `AVFrame::pts`. - */ - int_least64_t pts = 0; - - bool flushed = false; - -public: - /** - * @param _graph a checked and configured AVFilterGraph - * @param _buffer_src an "abuffer" filter which serves as - * input - * @param _buffer_sink an "abuffersink" filter which serves as - * output - */ - FfmpegFilter(const AudioFormat &in_audio_format, - const AudioFormat &_out_audio_format, - Ffmpeg::FilterGraph &&_graph, - AVFilterContext &_buffer_src, - AVFilterContext &_buffer_sink) noexcept; - - /* virtual methods from class Filter */ - std::span FilterPCM(std::span src) override; - std::span ReadMore() override; - std::span Flush() override; - -private: - std::span ReadOutput(); -}; diff --git a/src/filter/plugins/FfmpegFilterPlugin.cxx b/src/filter/plugins/FfmpegFilterPlugin.cxx deleted file mode 100644 index 65b7af3..0000000 --- a/src/filter/plugins/FfmpegFilterPlugin.cxx +++ /dev/null @@ -1,114 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#include "FfmpegFilterPlugin.hxx" -#include "FfmpegFilter.hxx" -#include "filter/FilterPlugin.hxx" -#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 { - 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; -}; - -/** - * Fallback for PreparedFfmpegFilter::Open() just in case the filter's - * native output format could not be determined. - * - * TODO: improve the MPD filter API to allow returning the output - * format later, and eliminate this kludge - */ -static auto -OpenWithAformat(const char *graph_string, AudioFormat &in_audio_format) -{ - Ffmpeg::FilterGraph graph; - - auto &buffer_src = - Ffmpeg::MakeAudioBufferSource(in_audio_format, *graph); - - auto &buffer_sink = Ffmpeg::MakeAudioBufferSink(*graph); - - AudioFormat out_audio_format = in_audio_format; - auto &aformat = Ffmpeg::MakeAformat(out_audio_format, *graph); - - if (int error = avfilter_link(&aformat, 0, &buffer_sink, 0); error < 0) - throw MakeFfmpegError(error, "avfilter_link() failed"); - - graph.ParseSingleInOut(graph_string, aformat, buffer_src); - graph.CheckAndConfigure(); - - return std::make_unique(in_audio_format, - out_audio_format, - std::move(graph), - buffer_src, - buffer_sink); -} - -std::unique_ptr -PreparedFfmpegFilter::Open(AudioFormat &in_audio_format) -{ - Ffmpeg::FilterGraph graph; - - auto &buffer_src = - Ffmpeg::MakeAudioBufferSource(in_audio_format, *graph); - - auto &buffer_sink = Ffmpeg::MakeAudioBufferSink(*graph); - - /* if the filter's output format is not supported by MPD, this - "aformat" filter is inserted at the end and takes care for - the required conversion */ - auto &aformat = Ffmpeg::MakeAutoAformat(*graph); - - if (int error = avfilter_link(&aformat, 0, &buffer_sink, 0); error < 0) - throw MakeFfmpegError(error, "avfilter_link() failed"); - - graph.ParseSingleInOut(graph_string, aformat, buffer_src); - graph.CheckAndConfigure(); - - const auto out_audio_format = - Ffmpeg::DetectFilterOutputFormat(in_audio_format, buffer_src, - buffer_sink); - - if (!out_audio_format.IsDefined()) - /* the filter's native output format could not be - determined yet, but we need to know it now; as a - workaround for this MPD API deficiency, try again - with an "aformat" filter which forces a specific - output format */ - return OpenWithAformat(graph_string, in_audio_format); - - return std::make_unique(in_audio_format, - out_audio_format, - std::move(graph), - buffer_src, - 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 deleted file mode 100644 index e95e7a5..0000000 --- a/src/filter/plugins/FfmpegFilterPlugin.hxx +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#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/HdcdFilterPlugin.cxx b/src/filter/plugins/HdcdFilterPlugin.cxx deleted file mode 100644 index 08f3166..0000000 --- a/src/filter/plugins/HdcdFilterPlugin.cxx +++ /dev/null @@ -1,79 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#include "HdcdFilterPlugin.hxx" -#include "FfmpegFilter.hxx" -#include "filter/FilterPlugin.hxx" -#include "filter/Filter.hxx" -#include "filter/NullFilter.hxx" -#include "filter/Prepared.hxx" -#include "lib/ffmpeg/Filter.hxx" -#include "pcm/AudioFormat.hxx" - -static constexpr const char *hdcd_graph = "hdcd"; - -[[gnu::pure]] -static bool -MaybeHdcd(const AudioFormat &audio_format) noexcept -{ - return audio_format.sample_rate == 44100 && - audio_format.format == SampleFormat::S16 && - audio_format.channels == 2; -} - -static auto -OpenHdcdFilter(AudioFormat &in_audio_format) -{ - Ffmpeg::FilterGraph graph; - - auto &buffer_src = - Ffmpeg::MakeAudioBufferSource(in_audio_format, - *graph); - - auto &buffer_sink = Ffmpeg::MakeAudioBufferSink(*graph); - - graph.ParseSingleInOut(hdcd_graph, buffer_sink, buffer_src); - graph.CheckAndConfigure(); - - auto out_audio_format = in_audio_format; - // TODO: convert to 32 bit only if HDCD actually detected - out_audio_format.format = SampleFormat::S32; - - return std::make_unique(in_audio_format, - out_audio_format, - std::move(graph), - buffer_src, - buffer_sink); -} - -class PreparedHdcdFilter final : public PreparedFilter { -public: - /* virtual methods from class PreparedFilter */ - std::unique_ptr Open(AudioFormat &af) override; -}; - -std::unique_ptr -PreparedHdcdFilter::Open(AudioFormat &audio_format) -{ - if (MaybeHdcd(audio_format)) - return OpenHdcdFilter(audio_format); - else - /* this cannot be HDCD, so let's copy as-is using - NullFilter */ - return std::make_unique(audio_format); -} - -static std::unique_ptr -hdcd_filter_init(const ConfigBlock &) -{ - /* check if the graph can be parsed (and discard the - object) */ - Ffmpeg::FilterGraph().Parse(hdcd_graph); - - return std::make_unique(); -} - -const FilterPlugin hdcd_filter_plugin = { - "hdcd", - hdcd_filter_init, -}; diff --git a/src/filter/plugins/HdcdFilterPlugin.hxx b/src/filter/plugins/HdcdFilterPlugin.hxx deleted file mode 100644 index a8f2757..0000000 --- a/src/filter/plugins/HdcdFilterPlugin.hxx +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#ifndef MPD_HDCD_FILTER_PLUGIN_HXX -#define MPD_HDCD_FILTER_PLUGIN_HXX - -struct FilterPlugin; - -extern const FilterPlugin hdcd_filter_plugin; - -#endif diff --git a/src/filter/plugins/NormalizeFilterPlugin.cxx b/src/filter/plugins/NormalizeFilterPlugin.cxx deleted file mode 100644 index 51e239e..0000000 --- a/src/filter/plugins/NormalizeFilterPlugin.cxx +++ /dev/null @@ -1,73 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#include "NormalizeFilterPlugin.hxx" -#include "filter/FilterPlugin.hxx" -#include "filter/Filter.hxx" -#include "filter/Prepared.hxx" -#include "pcm/Buffer.hxx" -#include "pcm/AudioFormat.hxx" -#include "pcm/Normalizer.hxx" -#include "util/SpanCast.hxx" - -class NormalizeFilter final : public Filter { - PcmNormalizer normalizer; - - PcmBuffer buffer; - -public: - explicit NormalizeFilter(const AudioFormat &audio_format) - :Filter(audio_format) { - } - - NormalizeFilter(const NormalizeFilter &) = delete; - NormalizeFilter &operator=(const NormalizeFilter &) = delete; - - /* virtual methods from class Filter */ - void Reset() noexcept override { - normalizer.Reset(); - } - - std::span FilterPCM(std::span src) override; -}; - -class PreparedNormalizeFilter final : public PreparedFilter { -public: - /* virtual methods from class PreparedFilter */ - std::unique_ptr Open(AudioFormat &af) override; -}; - -static std::unique_ptr -normalize_filter_init([[maybe_unused]] const ConfigBlock &block) -{ - return std::make_unique(); -} - -std::unique_ptr -PreparedNormalizeFilter::Open(AudioFormat &audio_format) -{ - audio_format.format = SampleFormat::S16; - - return std::make_unique(audio_format); -} - -std::span -NormalizeFilter::FilterPCM(std::span _src) -{ - const auto src = FromBytesStrict(_src); - auto *dest = (int16_t *)buffer.GetT(src.size()); - - normalizer.ProcessS16(dest, src); - return std::as_bytes(std::span{dest, src.size()}); -} - -const FilterPlugin normalize_filter_plugin = { - "normalize", - normalize_filter_init, -}; - -std::unique_ptr -normalize_filter_prepare() noexcept -{ - return std::make_unique(); -} diff --git a/src/filter/plugins/NormalizeFilterPlugin.hxx b/src/filter/plugins/NormalizeFilterPlugin.hxx index 6c61617..641a772 100644 --- a/src/filter/plugins/NormalizeFilterPlugin.hxx +++ b/src/filter/plugins/NormalizeFilterPlugin.hxx @@ -1,17 +1,22 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Copyright The Music Player Daemon Project +// STUB FILE - Filter support removed for mpd-dbcreate #ifndef MPD_NORMALIZE_FILTER_PLUGIN_HXX #define MPD_NORMALIZE_FILTER_PLUGIN_HXX +#include "filter/Prepared.hxx" #include -struct FilterPlugin; -class PreparedFilter; +struct ConfigBlock; -extern const FilterPlugin normalize_filter_plugin; - -std::unique_ptr -normalize_filter_prepare() noexcept; +/** + * Stub implementation - filter support not needed for database creation + */ +inline std::unique_ptr +normalize_filter_prepare([[maybe_unused]] const ConfigBlock *block = nullptr) +{ + return nullptr; +} #endif diff --git a/src/filter/plugins/NullFilterPlugin.cxx b/src/filter/plugins/NullFilterPlugin.cxx deleted file mode 100644 index eaa14d7..0000000 --- a/src/filter/plugins/NullFilterPlugin.cxx +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -/** \file - * - * This filter plugin does nothing. That is not quite useful, except - * for testing the filter core, or as a template for new filter - * plugins. - */ - -#include "NullFilterPlugin.hxx" -#include "filter/FilterPlugin.hxx" -#include "filter/NullFilter.hxx" -#include "filter/Prepared.hxx" - -class PreparedNullFilter final : public PreparedFilter { -public: - std::unique_ptr Open(AudioFormat &af) override { - return std::make_unique(af); - } -}; - -static std::unique_ptr -null_filter_init([[maybe_unused]] const ConfigBlock &block) -{ - return std::make_unique(); -} - -const FilterPlugin null_filter_plugin = { - "null", - null_filter_init, -}; diff --git a/src/filter/plugins/NullFilterPlugin.hxx b/src/filter/plugins/NullFilterPlugin.hxx deleted file mode 100644 index 8bd793f..0000000 --- a/src/filter/plugins/NullFilterPlugin.hxx +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#ifndef MPD_NULL_FILTER_PLUGIN_HXX -#define MPD_NULL_FILTER_PLUGIN_HXX - -struct FilterPlugin; - -extern const FilterPlugin null_filter_plugin; - -#endif diff --git a/src/filter/plugins/ReplayGainFilterPlugin.cxx b/src/filter/plugins/ReplayGainFilterPlugin.cxx deleted file mode 100644 index a215e7a..0000000 --- a/src/filter/plugins/ReplayGainFilterPlugin.cxx +++ /dev/null @@ -1,217 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#include "ReplayGainFilterPlugin.hxx" -#include "filter/Filter.hxx" -#include "filter/Prepared.hxx" -#include "tag/ReplayGainInfo.hxx" -#include "config/ReplayGainConfig.hxx" -#include "mixer/Control.hxx" -#include "mixer/Mixer.hxx" -#include "mixer/Listener.hxx" -#include "pcm/AudioFormat.hxx" -#include "pcm/Volume.hxx" -#include "util/Domain.hxx" -#include "Log.hxx" - -#include -#include - -static constexpr Domain replay_gain_domain("replay_gain"); - -class ReplayGainFilter final : public Filter { - const ReplayGainConfig config; - - /** - * If set, then this hardware mixer is used for applying - * replay gain, instead of the software volume library. - */ - Mixer *const mixer; - - /** - * The base volume level for scale=1.0, between 1 and 100 - * (including). - */ - const unsigned base; - - ReplayGainMode mode = ReplayGainMode::OFF; - - ReplayGainInfo info; - - /** - * About the current volume: it is between 0 and a value that - * may or may not exceed #PCM_VOLUME_1. - * - * If the default value of true is used for replaygain_limit, the - * application of the volume to the signal will never cause clipping. - * - * On the other hand, if the user has set replaygain_limit to false, - * the chance of clipping is explicitly preferred if that's required to - * maintain a consistent audio level. Whether clipping will actually - * occur depends on what value the user is using for replaygain_preamp. - */ - PcmVolume pv; - -public: - ReplayGainFilter(const ReplayGainConfig &_config, bool allow_convert, - const AudioFormat &audio_format, - Mixer *_mixer, unsigned _base) - :Filter(audio_format), - config(_config), - mixer(_mixer), base(_base) { - info.Clear(); - - out_audio_format.format = pv.Open(out_audio_format.format, - allow_convert); - } - - void SetInfo(const ReplayGainInfo *_info) { - if (_info != nullptr) - info = *_info; - else - info.Clear(); - - Update(); - } - - void SetMode(ReplayGainMode _mode) { - if (_mode == mode) - /* no change */ - return; - - FmtDebug(replay_gain_domain, - "replay gain mode has changed {}->{}", - ToString(mode), ToString(_mode)); - - mode = _mode; - Update(); - } - - /** - * Recalculates the new volume after a property was changed. - */ - void Update(); - - /* virtual methods from class Filter */ - std::span FilterPCM(std::span src) override; -}; - -class PreparedReplayGainFilter final : public PreparedFilter { - const ReplayGainConfig config; - - /** - * If set, then this hardware mixer is used for applying - * replay gain, instead of the software volume library. - */ - Mixer *mixer = nullptr; - - /** - * Allow the class to convert to a different #SampleFormat to - * preserve quality? - */ - const bool allow_convert; - - /** - * The base volume level for scale=1.0, between 1 and 100 - * (including). - */ - unsigned base; - -public: - explicit PreparedReplayGainFilter(const ReplayGainConfig _config, - bool _allow_convert) - :config(_config), allow_convert(_allow_convert) {} - - void SetMixer(Mixer *_mixer, unsigned _base) { - assert(_mixer == nullptr || (_base > 0 && _base <= 100)); - - mixer = _mixer; - base = _base; - } - - /* virtual methods from class Filter */ - std::unique_ptr Open(AudioFormat &af) override; -}; - -void -ReplayGainFilter::Update() -{ - unsigned volume = PCM_VOLUME_1; - if (mode != ReplayGainMode::OFF) { - const auto &tuple = info.Get(mode); - float scale = tuple.CalculateScale(config); - FmtDebug(replay_gain_domain, "scale={}\n", scale); - - volume = pcm_float_to_volume(scale); - } - - if (mixer != nullptr) { - /* update the hardware mixer volume */ - - unsigned _volume = (volume * base) / PCM_VOLUME_1; - if (_volume > 100) - _volume = 100; - - try { - mixer->LockSetVolume(_volume); - - /* invoke the mixer's listener manually, just - in case the mixer implementation didn't do - that already (this depends on the - implementation) */ - mixer->listener.OnMixerVolumeChanged(*mixer, _volume); - } catch (...) { - LogError(std::current_exception(), - "Failed to update hardware mixer"); - } - } else - pv.SetVolume(volume); -} - -std::unique_ptr -NewReplayGainFilter(const ReplayGainConfig &config, - bool allow_convert) noexcept -{ - return std::make_unique(config, - allow_convert); -} - -std::unique_ptr -PreparedReplayGainFilter::Open(AudioFormat &af) -{ - return std::make_unique(config, allow_convert, - af, mixer, base); -} - -std::span -ReplayGainFilter::FilterPCM(std::span src) -{ - return mixer != nullptr - ? std::span{src} - : pv.Apply(src); -} - -void -replay_gain_filter_set_mixer(PreparedFilter &_filter, Mixer *mixer, - unsigned base) -{ - auto &filter = (PreparedReplayGainFilter &)_filter; - - filter.SetMixer(mixer, base); -} - -void -replay_gain_filter_set_info(Filter &_filter, const ReplayGainInfo *info) -{ - auto &filter = (ReplayGainFilter &)_filter; - - filter.SetInfo(info); -} - -void -replay_gain_filter_set_mode(Filter &_filter, ReplayGainMode mode) -{ - auto &filter = (ReplayGainFilter &)_filter; - - filter.SetMode(mode); -} diff --git a/src/filter/plugins/ReplayGainFilterPlugin.hxx b/src/filter/plugins/ReplayGainFilterPlugin.hxx index 7446dbb..0a012af 100644 --- a/src/filter/plugins/ReplayGainFilterPlugin.hxx +++ b/src/filter/plugins/ReplayGainFilterPlugin.hxx @@ -1,49 +1,47 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Copyright The Music Player Daemon Project +// STUB FILE - Filter support removed for mpd-dbcreate #ifndef MPD_REPLAY_GAIN_FILTER_PLUGIN_HXX #define MPD_REPLAY_GAIN_FILTER_PLUGIN_HXX -#include "ReplayGainMode.hxx" - +#include "filter/Prepared.hxx" #include +#include -class Filter; -class PreparedFilter; -class Mixer; struct ReplayGainConfig; -struct ReplayGainInfo; - -/** - * @param allow_convert allow the class to convert to a different - * #SampleFormat to preserve quality? - */ -std::unique_ptr -NewReplayGainFilter(const ReplayGainConfig &config, - bool allow_convert) noexcept; +enum class ReplayGainMode : uint8_t; /** - * Enables or disables the hardware mixer for applying replay gain. - * - * @param mixer the hardware mixer, or nullptr to fall back to software - * volume - * @param base the base volume level for scale=1.0, between 1 and 100 - * (including). + * Stub implementation - filter support not needed for database creation */ -void -replay_gain_filter_set_mixer(PreparedFilter &_filter, Mixer *mixer, - unsigned base); - -/** - * Sets a new #ReplayGainInfo at the beginning of a new song. - * - * @param info the new #ReplayGainInfo value, or nullptr if no replay - * gain data is available for the current song - */ -void -replay_gain_filter_set_info(Filter &filter, const ReplayGainInfo *info); - -void -replay_gain_filter_set_mode(Filter &filter, ReplayGainMode mode); +inline std::unique_ptr +NewReplayGainFilter([[maybe_unused]] const ReplayGainConfig &config, + [[maybe_unused]] bool allow_convert = false) +{ + return nullptr; +} + +inline void +replay_gain_filter_set_mode([[maybe_unused]] Filter &, + [[maybe_unused]] ReplayGainMode) noexcept +{ + // No-op stub +} + +inline void +replay_gain_filter_set_info([[maybe_unused]] Filter &, + [[maybe_unused]] const void *) noexcept +{ + // No-op stub +} + +inline void +replay_gain_filter_set_mixer([[maybe_unused]] PreparedFilter &, + [[maybe_unused]] class Mixer *, + [[maybe_unused]] unsigned) noexcept +{ + // No-op stub +} #endif diff --git a/src/filter/plugins/RouteFilterPlugin.cxx b/src/filter/plugins/RouteFilterPlugin.cxx deleted file mode 100644 index daf58da..0000000 --- a/src/filter/plugins/RouteFilterPlugin.cxx +++ /dev/null @@ -1,260 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -/** \file - * - * This filter copies audio data between channels. Useful for - * upmixing mono/stereo audio to surround speaker configurations. - * - * Its configuration consists of a "filter" section with a single - * "routes" entry, formatted as: \\ - * routes "0>1, 1>0, 2>2, 3>3, 3>4" \\ - * where each pair of numbers signifies a set of channels. - * Each source>dest pair leads to the data from channel #source - * being copied to channel #dest in the output. - * - * Example: \\ - * routes "0>0, 1>1, 0>2, 1>3"\\ - * upmixes stereo audio to a 4-speaker system, copying the front-left - * (0) to front left (0) and rear left (2), copying front-right (1) to - * front-right (1) and rear-right (3). - * - * If multiple sources are copied to the same destination channel, only - * one of them takes effect. - */ - -#include "RouteFilterPlugin.hxx" -#include "config/Block.hxx" -#include "filter/FilterPlugin.hxx" -#include "filter/Filter.hxx" -#include "filter/Prepared.hxx" -#include "pcm/AudioFormat.hxx" -#include "pcm/Buffer.hxx" -#include "pcm/Silence.hxx" -#include "lib/fmt/RuntimeError.hxx" -#include "util/StringStrip.hxx" - -#include -#include -#include - -#include -#include - -class RouteFilter final : public Filter { - /** - * The set of copy operations to perform on each sample - * The index is an output channel to use, the value is - * a corresponding input channel from which to take the - * data. A -1 means "no source" - */ - const std::array sources; - - /** - * The actual input format of our signal, once opened - */ - const AudioFormat input_format; - - /** - * The size, in bytes, of each multichannel frame in the - * input buffer - */ - const size_t input_frame_size; - - /** - * The size, in bytes, of each multichannel frame in the - * output buffer - */ - size_t output_frame_size; - - /** - * The output buffer used last time around, can be reused if the size doesn't differ. - */ - PcmBuffer output_buffer; - -public: - RouteFilter(const AudioFormat &audio_format, unsigned out_channels, - const std::array &_sources); - - /* virtual methods from class Filter */ - std::span FilterPCM(std::span src) override; -}; - -class PreparedRouteFilter final : public PreparedFilter { - /** - * The minimum number of channels we need for output - * to be able to perform all the copies the user has specified - */ - unsigned min_output_channels; - - /** - * The minimum number of input channels we need to - * copy all the data the user has requested. If fewer - * than this many are supplied by the input, undefined - * copy operations are given zeroed sources in stead. - */ - unsigned min_input_channels; - - /** - * The set of copy operations to perform on each sample - * The index is an output channel to use, the value is - * a corresponding input channel from which to take the - * data. A -1 means "no source" - */ - std::array sources; - -public: - /** - * Parse the "routes" section, a string on the form - * a>b, c>d, e>f, ... - * where a... are non-unique, non-negative integers - * and input channel a gets copied to output channel b, etc. - * @param block the configuration block to read - * @param filter a route_filter whose min_channels and sources[] to set - */ - explicit PreparedRouteFilter(const ConfigBlock &block); - - /* virtual methods from class PreparedFilter */ - std::unique_ptr Open(AudioFormat &af) override; -}; - -PreparedRouteFilter::PreparedRouteFilter(const ConfigBlock &block) -{ - /* TODO: - * With a more clever way of marking "don't copy to output N", - * This could easily be merged into a single loop with some - * dynamic realloc() instead of one count run and one malloc(). - */ - - sources.fill(-1); - - min_input_channels = 0; - min_output_channels = 0; - - // A cowardly default, just passthrough stereo - const char *routes = block.GetBlockValue("routes", "0>0, 1>1"); - while (true) { - routes = StripLeft(routes); - - char *endptr; - const unsigned source = strtoul(routes, &endptr, 10); - endptr = StripLeft(endptr); - if (endptr == routes || *endptr != '>') - throw std::runtime_error("Malformed 'routes' specification"); - - if (source >= MAX_CHANNELS) - throw FmtRuntimeError("Invalid source channel number: {}", - source); - - if (source >= min_input_channels) - min_input_channels = source + 1; - - routes = StripLeft(endptr + 1); - - unsigned dest = strtoul(routes, &endptr, 10); - endptr = StripLeft(endptr); - if (endptr == routes) - throw std::runtime_error("Malformed 'routes' specification"); - - if (dest >= MAX_CHANNELS) - throw FmtRuntimeError("Invalid destination channel number: {}", - dest); - - if (dest >= min_output_channels) - min_output_channels = dest + 1; - - sources[dest] = source; - - routes = endptr; - - if (*routes == 0) - break; - - if (*routes != ',') - throw std::runtime_error("Malformed 'routes' specification"); - - ++routes; - } -} - -static std::unique_ptr -route_filter_init(const ConfigBlock &block) -{ - return std::make_unique(block); -} - -RouteFilter::RouteFilter(const AudioFormat &audio_format, - unsigned out_channels, - const std::array &_sources) - :Filter(audio_format), sources(_sources), input_format(audio_format), - input_frame_size(input_format.GetFrameSize()) -{ - // Decide on an output format which has enough channels, - // and is otherwise identical - out_audio_format.channels = out_channels; - - // Precalculate this simple value, to speed up allocation later - output_frame_size = out_audio_format.GetFrameSize(); -} - -std::unique_ptr -PreparedRouteFilter::Open(AudioFormat &audio_format) -{ - return std::make_unique(audio_format, min_output_channels, - sources); -} - -std::span -RouteFilter::FilterPCM(std::span src) -{ - size_t number_of_frames = src.size() / input_frame_size; - - const size_t bytes_per_frame_per_channel = input_format.GetSampleSize(); - - // A moving pointer that always refers to channel 0 in the input, at the currently handled frame - const auto *base_source = (const uint8_t *)src.data(); - - // Grow our reusable buffer, if needed, and set the moving pointer - const size_t result_size = number_of_frames * output_frame_size; - void *const result = output_buffer.Get(result_size); - - // A moving pointer that always refers to the currently filled channel of the currently handled frame, in the output - auto *chan_destination = (std::byte *)result; - - // Perform our copy operations, with N input channels and M output channels - for (unsigned int s=0; s= input_format.channels) { - // No source for this destination output, - // give it zeroes as input - PcmSilence({chan_destination, bytes_per_frame_per_channel}, - input_format.format); - } else { - // Get the data from channel sources[c] - // and copy it to the output - const uint8_t *data = base_source + - (sources[c] * bytes_per_frame_per_channel); - memcpy(chan_destination, - data, - bytes_per_frame_per_channel); - } - // Move on to the next output channel - chan_destination += bytes_per_frame_per_channel; - } - - - // Go on to the next N input samples - base_source += input_frame_size; - } - - // Here it is, ladies and gentlemen! Rerouted data! - return { (const std::byte *)result, result_size }; -} - -const FilterPlugin route_filter_plugin = { - "route", - route_filter_init, -}; diff --git a/src/filter/plugins/RouteFilterPlugin.hxx b/src/filter/plugins/RouteFilterPlugin.hxx deleted file mode 100644 index 7bba6e2..0000000 --- a/src/filter/plugins/RouteFilterPlugin.hxx +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#ifndef MPD_ROUTE_FILTER_PLUGIN_HXX -#define MPD_ROUTE_FILTER_PLUGIN_HXX - -struct FilterPlugin; - -extern const FilterPlugin route_filter_plugin; - -#endif diff --git a/src/filter/plugins/TwoFilters.cxx b/src/filter/plugins/TwoFilters.cxx deleted file mode 100644 index 3b3fab9..0000000 --- a/src/filter/plugins/TwoFilters.cxx +++ /dev/null @@ -1,100 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#include "TwoFilters.hxx" -#include "pcm/AudioFormat.hxx" -#include "lib/fmt/AudioFormatFormatter.hxx" -#include "lib/fmt/RuntimeError.hxx" -#include "util/StringBuffer.hxx" - -void -TwoFilters::Reset() noexcept -{ - assert(first); - assert(second); - - first->Reset(); - second->Reset(); -} - -std::span -TwoFilters::FilterPCM(std::span src) -{ - assert(first); - assert(second); - - if (const auto dest = first->FilterPCM(src); dest.empty()) [[unlikely]] - /* no output from the first filter; pass the empty - buffer on, do not call the second filter */ - return dest; - else - /* pass output from the first filter to the second - filter and return its result */ - return second->FilterPCM(dest); -} - -std::span -TwoFilters::ReadMore() -{ - assert(first); - assert(second); - - /* first read all remaining data from the second filter */ - if (auto result = second->ReadMore(); !result.empty()) - return result; - - /* now read more data from the first filter and process it - with the second filter */ - if (auto result = first->ReadMore(); !result.empty()) - /* output from the first Filter must be filtered by - the second Filter */ - return second->FilterPCM(result); - - /* both filters have been queried and there's no more data */ - return {}; -} - -std::span -TwoFilters::Flush() -{ - assert(second); - - /* first read all remaining data from the second filter */ - if (auto result = second->ReadMore(); !result.empty()) - return result; - - /* now flush the first filter and process it with the second - filter */ - if (first) { - if (auto result = first->Flush(); !result.empty()) - /* output from the first Filter must be - filtered by the second Filter */ - return second->FilterPCM(result); - - /* the first filter is flushed completely and we don't - need it anymore; any further method calls that - would use it are illegal according to the Filter - API docs */ - first.reset(); - } - - /* finally flush the second filter */ - return second->Flush(); -} - -std::unique_ptr -PreparedTwoFilters::Open(AudioFormat &audio_format) -{ - auto a = first->Open(audio_format); - - const auto &a_out_format = a->GetOutAudioFormat(); - auto b_in_format = a_out_format; - auto b = second->Open(b_in_format); - - if (b_in_format != a_out_format) - throw FmtRuntimeError("Audio format not supported by filter {:?}: {}", - second_name, a_out_format); - - return std::make_unique(std::move(a), - std::move(b)); -} diff --git a/src/filter/plugins/TwoFilters.hxx b/src/filter/plugins/TwoFilters.hxx index 0bd2f6c..ed679f9 100644 --- a/src/filter/plugins/TwoFilters.hxx +++ b/src/filter/plugins/TwoFilters.hxx @@ -1,66 +1,29 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Copyright The Music Player Daemon Project +// STUB FILE - Filter support removed for mpd-dbcreate -#pragma once +#ifndef MPD_TWO_FILTERS_HXX +#define MPD_TWO_FILTERS_HXX -#include "filter/Filter.hxx" #include "filter/Prepared.hxx" - #include -#include - -/** - * A #Filter implementation which chains two other filters. - */ -class TwoFilters final : public Filter { - std::unique_ptr first, second; - -public: - template - TwoFilters(F &&_first, S &&_second) noexcept - :Filter(_second->GetOutAudioFormat()), - first(std::forward(_first)), - second(std::forward(_second)) {} - - // virtual methods from class Filter - void Reset() noexcept override; - std::span FilterPCM(std::span src) override; - std::span ReadMore() override; - std::span Flush() override; -}; /** - * Like #TwoFilters, but implements the #PreparedFilter interface. + * Stub implementation - filter support not needed for database creation */ -class PreparedTwoFilters final : public PreparedFilter { - std::unique_ptr first, second; - std::string second_name; - -public: - template - PreparedTwoFilters(F &&_first, S &&_second, N &&_second_name) noexcept - :first(std::forward(_first)), - second(std::forward(_second)), - second_name(std::forward(_second_name)) {} - - std::unique_ptr Open(AudioFormat &audio_format) override; -}; - -/** - * Create a #PreparedTwoFilters instance, but only if both parameters - * are not nullptr. - */ -template -static std::unique_ptr -ChainFilters(F &&first, S &&second, N &&second_name) noexcept +inline std::unique_ptr +PreparedTwoFilters([[maybe_unused]] std::unique_ptr a, + [[maybe_unused]] std::unique_ptr b) { - if (!second) - return std::forward(first); - - if (!first) - return std::forward(second); + return nullptr; +} - return std::make_unique(std::forward(first), - std::forward(second), - std::forward(second_name)); +inline std::unique_ptr +ChainFilters([[maybe_unused]] std::unique_ptr a, + [[maybe_unused]] std::unique_ptr b, + [[maybe_unused]] const char *name = nullptr) +{ + return nullptr; } + +#endif diff --git a/src/filter/plugins/VolumeFilterPlugin.cxx b/src/filter/plugins/VolumeFilterPlugin.cxx deleted file mode 100644 index 93360a5..0000000 --- a/src/filter/plugins/VolumeFilterPlugin.cxx +++ /dev/null @@ -1,71 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Copyright The Music Player Daemon Project - -#include "VolumeFilterPlugin.hxx" -#include "filter/Filter.hxx" -#include "filter/Prepared.hxx" -#include "pcm/Volume.hxx" -#include "pcm/AudioFormat.hxx" - -class VolumeFilter final : public Filter { - PcmVolume pv; - -public: - explicit VolumeFilter(const AudioFormat &audio_format) - :Filter(audio_format) { - out_audio_format.format = pv.Open(out_audio_format.format, - true); - } - - [[nodiscard]] unsigned GetVolume() const noexcept { - return pv.GetVolume(); - } - - void SetVolume(unsigned _volume) noexcept { - pv.SetVolume(_volume); - } - - /* virtual methods from class Filter */ - std::span FilterPCM(std::span src) override; -}; - -class PreparedVolumeFilter final : public PreparedFilter { -public: - /* virtual methods from class Filter */ - std::unique_ptr Open(AudioFormat &af) override; -}; - -std::unique_ptr -PreparedVolumeFilter::Open(AudioFormat &audio_format) -{ - return std::make_unique(audio_format); -} - -std::span -VolumeFilter::FilterPCM(std::span src) -{ - return pv.Apply(src); -} - -std::unique_ptr -volume_filter_prepare() noexcept -{ - return std::make_unique(); -} - -unsigned -volume_filter_get(const Filter *_filter) noexcept -{ - const auto *filter = - (const VolumeFilter *)_filter; - - return filter->GetVolume(); -} - -void -volume_filter_set(Filter *_filter, unsigned volume) noexcept -{ - auto *filter = (VolumeFilter *)_filter; - - filter->SetVolume(volume); -} diff --git a/src/filter/plugins/VolumeFilterPlugin.hxx b/src/filter/plugins/VolumeFilterPlugin.hxx index 9c119f8..0a831f9 100644 --- a/src/filter/plugins/VolumeFilterPlugin.hxx +++ b/src/filter/plugins/VolumeFilterPlugin.hxx @@ -1,21 +1,28 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Copyright The Music Player Daemon Project +// STUB FILE - Filter support removed for mpd-dbcreate #ifndef MPD_VOLUME_FILTER_PLUGIN_HXX #define MPD_VOLUME_FILTER_PLUGIN_HXX +#include "filter/Prepared.hxx" #include -class PreparedFilter; class Filter; -std::unique_ptr -volume_filter_prepare() noexcept; +/** + * Stub implementation - filter support not needed for database creation + */ +inline void +volume_filter_set(Filter *, unsigned) noexcept +{ + // No-op stub +} -unsigned -volume_filter_get(const Filter *filter) noexcept; - -void -volume_filter_set(Filter *filter, unsigned volume) noexcept; +inline std::unique_ptr +volume_filter_prepare() noexcept +{ + return nullptr; +} #endif diff --git a/src/filter/plugins/meson.build b/src/filter/plugins/meson.build deleted file mode 100644 index aef504a..0000000 --- a/src/filter/plugins/meson.build +++ /dev/null @@ -1,38 +0,0 @@ -filter_plugins_sources = [] -filter_plugins_deps = [fmt_dep] - -if libavfilter_dep.found() - filter_plugins_sources += [ - 'FfmpegFilter.cxx', - 'FfmpegFilterPlugin.cxx', - 'HdcdFilterPlugin.cxx', - ] - filter_plugins_deps += ffmpeg_dep -endif - -filter_plugins = static_library( - 'filter_plugins', - 'NullFilterPlugin.cxx', - 'TwoFilters.cxx', - 'AutoConvertFilterPlugin.cxx', - 'ConvertFilterPlugin.cxx', - 'RouteFilterPlugin.cxx', - 'NormalizeFilterPlugin.cxx', - 'ReplayGainFilterPlugin.cxx', - 'VolumeFilterPlugin.cxx', - filter_plugins_sources, - include_directories: inc, - dependencies: [ - filter_plugins_deps, - log_dep, - ], -) - -filter_plugins_dep = declare_dependency( - link_with: filter_plugins, - dependencies: [ - filter_api_dep, - pcm_dep, - config_dep, - ] + filter_plugins_deps, -) diff --git a/src/output/meson.build b/src/output/meson.build index 37fa768..093e5bb 100644 --- a/src/output/meson.build +++ b/src/output/meson.build @@ -11,7 +11,7 @@ output_api = static_library( output_api_dep = declare_dependency( link_with: output_api, dependencies: [ - filter_plugins_dep, + # filter_plugins_dep, # Removed - not needed for database creation mixer_plugins_dep, ], ) @@ -56,7 +56,7 @@ output_glue = static_library( output_glue_dep = declare_dependency( link_with: output_glue, dependencies: [ - filter_glue_dep, + # filter_glue_dep, # Removed - not needed for database creation mixer_plugins_dep, ], ) diff --git a/test/meson.build b/test/meson.build index 3c736cb..72be9df 100644 --- a/test/meson.build +++ b/test/meson.build @@ -482,16 +482,17 @@ test( protocol: 'gtest', ) -executable( - 'run_filter', - 'run_filter.cxx', - 'ReadFrames.cxx', - include_directories: inc, - dependencies: [ - filter_glue_dep, - cmdline_dep, - ], -) +# Removed - filter plugins not needed for database creation +# executable( +# 'run_filter', +# 'run_filter.cxx', +# 'ReadFrames.cxx', +# include_directories: inc, +# dependencies: [ +# filter_glue_dep, +# cmdline_dep, +# ], +# ) executable( 'software_volume', @@ -546,28 +547,28 @@ executable( ) # -# Encoder +# Encoder - Removed, not needed for database creation # -if need_encoder - executable( - 'run_encoder', - 'run_encoder.cxx', - include_directories: inc, - dependencies: [ - encoder_glue_dep, - ], - ) - - executable( - 'test_vorbis_encoder', - 'test_vorbis_encoder.cxx', - include_directories: inc, - dependencies: [ - encoder_glue_dep, - ], - ) -endif +# if need_encoder +# executable( +# 'run_encoder', +# 'run_encoder.cxx', +# include_directories: inc, +# dependencies: [ +# encoder_glue_dep, +# ], +# ) +# +# executable( +# 'test_vorbis_encoder', +# 'test_vorbis_encoder.cxx', +# include_directories: inc, +# dependencies: [ +# encoder_glue_dep, +# ], +# ) +# endif # # Output @@ -579,7 +580,7 @@ executable( include_directories: inc, dependencies: [ output_registry_dep, - encoder_glue_dep, + # encoder_glue_dep, # Removed - not needed for database creation event_dep, cmdline_dep, ],