diff options
author | Max Kellermann <max@duempel.org> | 2009-07-06 10:01:02 +0200 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2009-07-06 10:01:02 +0200 |
commit | cd9c0a6b3e0a113d873483d214e1be1c37301b06 (patch) | |
tree | e4d5c342d3b7fedb2c1a257effc9c6b0d94c6051 | |
parent | c372c3756b24d2ecd879f1f857ccdbf421f3be33 (diff) | |
download | mpd-cd9c0a6b3e0a113d873483d214e1be1c37301b06.tar.gz mpd-cd9c0a6b3e0a113d873483d214e1be1c37301b06.tar.xz mpd-cd9c0a6b3e0a113d873483d214e1be1c37301b06.zip |
filter/convert: new filter which calls pcm_convert() on demand
-rw-r--r-- | Makefile.am | 11 | ||||
-rw-r--r-- | src/filter/convert_filter_plugin.c | 154 | ||||
-rw-r--r-- | src/filter/convert_filter_plugin.h | 36 | ||||
-rw-r--r-- | src/filter_registry.h | 1 |
4 files changed, 201 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am index 156c1c2da..11397ac3d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -46,6 +46,7 @@ mpd_headers = \ src/filter_plugin.h \ src/filter_registry.h \ src/filter/chain_filter_plugin.h \ + src/filter/convert_filter_plugin.h \ src/filter/volume_filter_plugin.h \ src/buffer2array.h \ src/command.h \ @@ -585,6 +586,7 @@ endif FILTER_SRC = \ src/filter/null_filter_plugin.c \ src/filter/chain_filter_plugin.c \ + src/filter/convert_filter_plugin.c \ src/filter/volume_filter_plugin.c @@ -685,15 +687,22 @@ test_read_tags_SOURCES = test/read_tags.c \ test_run_filter_CPPFLAGS = $(AM_CPPFLAGS) test_run_filter_LDADD = $(MPD_LIBS) \ + $(SAMPLERATE_LIBS) \ $(GLIB_LIBS) test_run_filter_SOURCES = test/run_filter.c \ src/filter_plugin.c \ src/filter_registry.c \ src/conf.c src/buffer2array.c src/utils.c \ - src/pcm_volume.c \ + src/pcm_volume.c src/pcm_convert.c \ + src/pcm_format.c src/pcm_channels.c src/pcm_dither.c \ + src/pcm_resample.c src/pcm_resample_fallback.c \ src/audio_parser.c \ $(FILTER_SRC) +if HAVE_LIBSAMPLERATE +test_run_filter_SOURCES += src/pcm_resample_libsamplerate.c +endif + test_run_encoder_SOURCES = test/run_encoder.c \ src/conf.c src/buffer2array.c \ src/utils.c \ diff --git a/src/filter/convert_filter_plugin.c b/src/filter/convert_filter_plugin.c new file mode 100644 index 000000000..f4d03ebef --- /dev/null +++ b/src/filter/convert_filter_plugin.c @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2003-2009 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "filter/convert_filter_plugin.h" +#include "filter_plugin.h" +#include "filter_internal.h" +#include "filter_registry.h" +#include "conf.h" +#include "pcm_convert.h" +#include "audio_format.h" +#include "poison.h" + +#include <assert.h> +#include <string.h> + +struct convert_filter { + struct filter base; + + /** + * The current convert, from 0 to #PCM_CONVERT_1. + */ + unsigned convert; + + /** + * The input audio format; PCM data is passed to the filter() + * method in this format. + */ + struct audio_format in_audio_format; + + /** + * The output audio format; the consumer of this plugin + * expects PCM data in this format. This defaults to + * #in_audio_format, and can be set with convert_filter_set(). + */ + struct audio_format out_audio_format; + + struct pcm_convert_state state; +}; + +static inline GQuark +convert_quark(void) +{ + return g_quark_from_static_string("pcm_convert"); +} + +static struct filter * +convert_filter_init(G_GNUC_UNUSED const struct config_param *param, + G_GNUC_UNUSED GError **error_r) +{ + struct convert_filter *filter = g_new(struct convert_filter, 1); + + filter_init(&filter->base, &convert_filter_plugin); + return &filter->base; +} + +static void +convert_filter_finish(struct filter *filter) +{ + g_free(filter); +} + +static const struct audio_format * +convert_filter_open(struct filter *_filter, + const struct audio_format *audio_format, + G_GNUC_UNUSED GError **error_r) +{ + struct convert_filter *filter = (struct convert_filter *)_filter; + + assert(audio_format_valid(audio_format)); + + filter->in_audio_format = filter->out_audio_format = *audio_format; + pcm_convert_init(&filter->state); + + return audio_format; +} + +static void +convert_filter_close(struct filter *_filter) +{ + struct convert_filter *filter = (struct convert_filter *)_filter; + + pcm_convert_deinit(&filter->state); + + poison_undefined(&filter->in_audio_format, + sizeof(filter->in_audio_format)); + poison_undefined(&filter->out_audio_format, + sizeof(filter->out_audio_format)); +} + +static const void * +convert_filter_filter(struct filter *_filter, const void *src, size_t src_size, + size_t *dest_size_r, GError **error_r) +{ + struct convert_filter *filter = (struct convert_filter *)_filter; + const void *dest; + + if (audio_format_equals(&filter->in_audio_format, + &filter->out_audio_format)) { + /* optimized special case: no-op */ + *dest_size_r = src_size; + return src; + } + + dest = pcm_convert(&filter->state, &filter->in_audio_format, + src, src_size, + &filter->out_audio_format, dest_size_r); + if (dest == NULL) { + g_set_error(error_r, convert_quark(), 0, + "pcm_convert() has failed"); + return NULL; + } + + return dest; +} + +const struct filter_plugin convert_filter_plugin = { + .name = "convert", + .init = convert_filter_init, + .finish = convert_filter_finish, + .open = convert_filter_open, + .close = convert_filter_close, + .filter = convert_filter_filter, +}; + +void +convert_filter_set(struct filter *_filter, + const struct audio_format *out_audio_format) +{ + struct convert_filter *filter = (struct convert_filter *)_filter; + + assert(filter != NULL); + assert(audio_format_valid(&filter->in_audio_format)); + assert(audio_format_valid(&filter->out_audio_format)); + assert(out_audio_format != NULL); + assert(audio_format_valid(out_audio_format)); + + filter->out_audio_format = *out_audio_format; +} diff --git a/src/filter/convert_filter_plugin.h b/src/filter/convert_filter_plugin.h new file mode 100644 index 000000000..8d370b0cb --- /dev/null +++ b/src/filter/convert_filter_plugin.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2003-2009 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef CONVERT_FILTER_PLUGIN_H +#define CONVERT_FILTER_PLUGIN_H + +struct filter; +struct audio_format; + +/** + * 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. + */ +void +convert_filter_set(struct filter *filter, + const struct audio_format *out_audio_format); + +#endif diff --git a/src/filter_registry.h b/src/filter_registry.h index 0eb4b8f03..7eb7f7038 100644 --- a/src/filter_registry.h +++ b/src/filter_registry.h @@ -28,6 +28,7 @@ extern const struct filter_plugin null_filter_plugin; extern const struct filter_plugin chain_filter_plugin; +extern const struct filter_plugin convert_filter_plugin; extern const struct filter_plugin volume_filter_plugin; const struct filter_plugin * |