diff options
author | Miguel Freitas <miguelfreitas@users.sourceforge.net> | 2005-07-16 16:36:59 +0000 |
---|---|---|
committer | Miguel Freitas <miguelfreitas@users.sourceforge.net> | 2005-07-16 16:36:59 +0000 |
commit | 42e0f1003ad4685d441923f589a2c6518caa8367 (patch) | |
tree | 8be02288407eea49643d50f39d23ac6af12ab8d6 | |
parent | 923f954cb85c28f4b3443f6aa273ac87d59c9ccf (diff) | |
download | xine-lib-42e0f1003ad4685d441923f589a2c6518caa8367.tar.gz xine-lib-42e0f1003ad4685d441923f589a2c6518caa8367.tar.bz2 |
Reinhard Nissl's plugin to upmix mono to stereo
CVS patchset: 7642
CVS date: 2005/07/16 16:36:59
-rw-r--r-- | src/post/audio/Makefile.am | 2 | ||||
-rw-r--r-- | src/post/audio/audio_filters.c | 14 | ||||
-rw-r--r-- | src/post/audio/audio_filters.h | 3 | ||||
-rw-r--r-- | src/post/audio/upmix_mono.c | 367 |
4 files changed, 378 insertions, 8 deletions
diff --git a/src/post/audio/Makefile.am b/src/post/audio/Makefile.am index b208a71e9..a7dbe64bf 100644 --- a/src/post/audio/Makefile.am +++ b/src/post/audio/Makefile.am @@ -7,7 +7,7 @@ libdir = $(XINE_PLUGINDIR)/post lib_LTLIBRARIES = xineplug_post_audio_filters.la xineplug_post_audio_filters_la_SOURCES = \ - upmix.c filter.c window.c stretch.c audio_filters.c + upmix.c upmix_mono.c filter.c window.c stretch.c audio_filters.c xineplug_post_audio_filters_la_LIBADD = $(XINE_LIB) xineplug_post_audio_filters_la_LDFLAGS = -avoid-version -module @XINE_PLUGIN_MIN_SYMS@ -lm diff --git a/src/post/audio/audio_filters.c b/src/post/audio/audio_filters.c index c773dc7a0..06e0afb86 100644 --- a/src/post/audio/audio_filters.c +++ b/src/post/audio/audio_filters.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: audio_filters.c,v 1.2 2004/07/27 17:59:58 mroi Exp $ + * $Id: audio_filters.c,v 1.3 2005/07/16 16:36:59 miguelfreitas Exp $ * * catalog for audio filter plugins */ @@ -30,13 +30,15 @@ #include "audio_filters.h" -post_info_t upmix_special_info = { XINE_POST_TYPE_AUDIO_FILTER }; -post_info_t stretch_special_info = { XINE_POST_TYPE_AUDIO_FILTER }; +post_info_t upmix_special_info = { XINE_POST_TYPE_AUDIO_FILTER }; +post_info_t upmix_mono_special_info = { XINE_POST_TYPE_AUDIO_FILTER }; +post_info_t stretch_special_info = { XINE_POST_TYPE_AUDIO_FILTER }; plugin_info_t xine_plugin_info[] = { /* type, API, "name", version, special_info, init_function */ - { PLUGIN_POST, 9, "upmix", XINE_VERSION_CODE, &upmix_special_info, &upmix_init_plugin }, - { PLUGIN_POST, 9, "stretch", XINE_VERSION_CODE, &stretch_special_info, &stretch_init_plugin }, - { PLUGIN_NONE, 0, "", 0, NULL, NULL } + { PLUGIN_POST, 9, "upmix", XINE_VERSION_CODE, &upmix_special_info, &upmix_init_plugin }, + { PLUGIN_POST, 9, "upmix_mono", XINE_VERSION_CODE, &upmix_mono_special_info, &upmix_mono_init_plugin }, + { PLUGIN_POST, 9, "stretch", XINE_VERSION_CODE, &stretch_special_info, &stretch_init_plugin }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; diff --git a/src/post/audio/audio_filters.h b/src/post/audio/audio_filters.h index 365c13346..d60fa7e32 100644 --- a/src/post/audio/audio_filters.h +++ b/src/post/audio/audio_filters.h @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: audio_filters.h,v 1.1 2004/07/27 17:59:58 mroi Exp $ + * $Id: audio_filters.h,v 1.2 2005/07/16 16:36:59 miguelfreitas Exp $ * * catalog for audio filter plugins */ @@ -26,4 +26,5 @@ void *upmix_init_plugin(xine_t *xine, void *data); +void *upmix_mono_init_plugin(xine_t *xine, void *data); void *stretch_init_plugin(xine_t *xine, void *data); diff --git a/src/post/audio/upmix_mono.c b/src/post/audio/upmix_mono.c new file mode 100644 index 000000000..0be676d4e --- /dev/null +++ b/src/post/audio/upmix_mono.c @@ -0,0 +1,367 @@ +/* + * Copyright (C) 2000-2004 the xine project + * + * This file is part of xine, a free video player. + * + * xine 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. + * + * xine 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * Upmix audio filter for xine. + * (c) 2004 James Courtier-Dutton (James@superbug.demon.co.uk) + * This is an up-mix audio filter post plugin. + * It simply converts Mono into Stereo. + * + * $Id: upmix_mono.c,v 1.1 2005/07/16 16:36:59 miguelfreitas Exp $ + * + */ + +#include <stdio.h> + +#define LOG_MODULE "upmix_mono" +#define LOG_VERBOSE +/* +#define LOG +*/ + +#include "xineutils.h" +#include "post.h" + +#include "audio_filters.h" + +typedef struct upmix_mono_parameters_s { + int channel; +} upmix_mono_parameters_t; + +/* + * description of params struct + */ +START_PARAM_DESCR( upmix_mono_parameters_t ) +PARAM_ITEM( POST_PARAM_TYPE_INT, channel, NULL, 0, 5, 0, + "Select channel to upmix (duplicate) to stereo" ) +END_PARAM_DESCR( param_descr ) + + +typedef struct post_plugin_upmix_mono_s post_plugin_upmix_mono_t; + +typedef struct post_class_upmix_mono_s post_class_upmix_mono_t; + +struct post_class_upmix_mono_s { + post_class_t post_class; + + xine_t *xine; +}; + +struct post_plugin_upmix_mono_s { + post_plugin_t post; + + /* private data */ + int channels; + + upmix_mono_parameters_t params; + xine_post_in_t params_input; + int params_changed; + + pthread_mutex_t lock; + +}; + +/************************************************************************** + * upmix_mono parameters functions + *************************************************************************/ +static int set_parameters (xine_post_t *this_gen, void *param_gen) { + post_plugin_upmix_mono_t *this = (post_plugin_upmix_mono_t *)this_gen; + upmix_mono_parameters_t *param = (upmix_mono_parameters_t *)param_gen; + + pthread_mutex_lock (&this->lock); + memcpy( &this->params, param, sizeof(upmix_mono_parameters_t) ); + this->params_changed = 1; + pthread_mutex_unlock (&this->lock); + + return 1; +} +static int get_parameters (xine_post_t *this_gen, void *param_gen) { + post_plugin_upmix_mono_t *this = (post_plugin_upmix_mono_t *)this_gen; + upmix_mono_parameters_t *param = (upmix_mono_parameters_t *)param_gen; + + pthread_mutex_lock (&this->lock); + memcpy( param, &this->params, sizeof(upmix_mono_parameters_t) ); + pthread_mutex_unlock (&this->lock); + + return 1; +} + +static xine_post_api_descr_t * get_param_descr (void) { + return ¶m_descr; +} + +static char * get_help (void) { + return _("This filter will upmix a mono stream to stereo, by " + "duplicating channels. Alternatively, one may use this " + "plugin to listen just one channel of a given stream.\n" + ); +} + +static xine_post_api_t post_api = { + set_parameters, + get_parameters, + get_param_descr, + get_help, +}; + + +/************************************************************************** + * xine audio post plugin functions + *************************************************************************/ + +static int upmix_mono_port_open(xine_audio_port_t *port_gen, xine_stream_t *stream, + uint32_t bits, uint32_t rate, int mode) { + + post_audio_port_t *port = (post_audio_port_t *)port_gen; + post_plugin_upmix_mono_t *this = (post_plugin_upmix_mono_t *)port->post; + uint32_t capabilities; + + _x_post_rewire(&this->post); + _x_post_inc_usage(port); + + port->stream = stream; + port->bits = bits; + port->rate = rate; + port->mode = mode; + + this->channels = _x_ao_mode2channels(mode); + capabilities = port->original_port->get_capabilities(port->original_port); + + if (this->channels == 1 && (capabilities & AO_CAP_MODE_STEREO)) { + xprintf(stream->xine, XINE_VERBOSITY_LOG, + _(LOG_MODULE ": upmixing Mono to Stereo.\n")); + mode = AO_CAP_MODE_STEREO; + } else { + if ( this->channels != 1) + xprintf(stream->xine, XINE_VERBOSITY_LOG, + _(LOG_MODULE ": upmixing a single channel from original %d channels stream.\n"), this->channels); + else { + xprintf(stream->xine, XINE_VERBOSITY_LOG, + _(LOG_MODULE ": audio device not capable of AO_CAP_MODE_STEREO.\n")); + this->channels = 0; + } + } + + return port->original_port->open(port->original_port, stream, bits, rate, mode); +} + +static void upmix_mono_port_put_buffer(xine_audio_port_t *port_gen, + audio_buffer_t *buf, xine_stream_t *stream) { + + post_audio_port_t *port = (post_audio_port_t *)port_gen; + post_plugin_upmix_mono_t *this = (post_plugin_upmix_mono_t *)port->post; + + pthread_mutex_lock (&this->lock); + + if (this->channels == 1) + { + audio_buffer_t *buf0 = port->original_port->get_buffer(port->original_port); + audio_buffer_t *buf1 = port->original_port->get_buffer(port->original_port); + buf0->num_frames = buf->num_frames / 2; + buf1->num_frames = buf->num_frames - (buf->num_frames / 2); + buf0->vpts = buf->vpts; + buf1->vpts = 0; + buf0->frame_header_count = buf->frame_header_count; + buf1->frame_header_count = buf->frame_header_count; + buf0->first_access_unit = buf->first_access_unit; + buf1->first_access_unit = buf->first_access_unit; + /* FIXME: The audio buffer should contain this info. + * We should not have to get it from the open call. + */ + buf0->format.bits = buf->format.bits; + buf1->format.bits = buf->format.bits; + buf0->format.rate = buf->format.rate; + buf1->format.rate = buf->format.rate; + buf0->format.mode = AO_CAP_MODE_STEREO; + buf1->format.mode = AO_CAP_MODE_STEREO; + _x_extra_info_merge(buf0->extra_info, buf->extra_info); + _x_extra_info_merge(buf1->extra_info, buf->extra_info); + + { + int step = buf->format.bits / 8; + uint8_t *src = (uint8_t *)buf->mem; + uint8_t *dst0 = (uint8_t *)buf0->mem; + uint8_t *dst1 = (uint8_t *)buf1->mem; + + int i, k; + for (i = 0; i < buf->num_frames / 2; i++) + { + for (k = 0; k < step; k++) + *dst0++ = *src++; + + src -= step; + + for (k = 0; k < step; k++) + *dst0++ = *src++; + } + + for (i = buf->num_frames / 2; i < buf->num_frames; i++) + { + for (k = 0; k < step; k++) + *dst1++ = *src++; + + src -= step; + + for (k = 0; k < step; k++) + *dst1++ = *src++; + } + } + + /* pass data to original port */ + port->original_port->put_buffer(port->original_port, buf0, stream); + port->original_port->put_buffer(port->original_port, buf1, stream); + + /* free data from origial buffer */ + buf->num_frames = 0; /* UNDOCUMENTED, but hey, it works! Force old audio_out buffer free. */ + } + else if (this->channels) + { + audio_buffer_t *buf0 = port->original_port->get_buffer(port->original_port); + buf0->num_frames = buf->num_frames; + buf0->vpts = buf->vpts; + buf0->frame_header_count = buf->frame_header_count; + buf0->first_access_unit = buf->first_access_unit; + /* FIXME: The audio buffer should contain this info. + * We should not have to get it from the open call. + */ + buf0->format.bits = buf->format.bits; + buf0->format.rate = buf->format.rate; + buf0->format.mode = AO_CAP_MODE_STEREO; + _x_extra_info_merge(buf0->extra_info, buf->extra_info); + + { + int step = buf->format.bits / 8; + uint8_t *src = (uint8_t *)buf->mem; + uint8_t *dst0 = (uint8_t *)buf0->mem; + int cur_channel = this->params.channel; + int i, j, k; + + if( cur_channel >= this->channels ) + cur_channel = this->channels-1; + + src += cur_channel * step; + + for (i = 0; i < buf->num_frames; i++) + { + for (j = 0; j < this->channels; j++ ) + { + for (k = 0; k < step; k++) + *dst0++ = *(src+k); + } + src += this->channels * step; + } + } + + /* pass data to original port */ + port->original_port->put_buffer(port->original_port, buf0, stream); + + /* free data from origial buffer */ + buf->num_frames = 0; /* UNDOCUMENTED, but hey, it works! Force old audio_out buffer free. */ + } + + pthread_mutex_unlock (&this->lock); + + port->original_port->put_buffer(port->original_port, buf, stream); + + return; +} + +static void upmix_mono_dispose(post_plugin_t *this_gen) +{ + post_plugin_upmix_mono_t *this = (post_plugin_upmix_mono_t *)this_gen; + + if (_x_post_dispose(this_gen)) + free(this); +} + +/* plugin class functions */ +static post_plugin_t *upmix_mono_open_plugin(post_class_t *class_gen, int inputs, + xine_audio_port_t **audio_target, + xine_video_port_t **video_target) +{ + post_plugin_upmix_mono_t *this = (post_plugin_upmix_mono_t *)xine_xmalloc(sizeof(post_plugin_upmix_mono_t)); + post_in_t *input; + post_out_t *output; + xine_post_in_t *input_api; + post_audio_port_t *port; + upmix_mono_parameters_t init_params; + + if (!this || !audio_target || !audio_target[0]) { + free(this); + return NULL; + } + + _x_post_init(&this->post, 1, 0); + + init_params.channel = 0; + + pthread_mutex_init (&this->lock, NULL); + + set_parameters ((xine_post_t *)&this->post, &init_params); + + port = _x_post_intercept_audio_port(&this->post, audio_target[0], &input, &output); + port->new_port.open = upmix_mono_port_open; + port->new_port.put_buffer = upmix_mono_port_put_buffer; + + input_api = &this->params_input; + input_api->name = "parameters"; + input_api->type = XINE_POST_DATA_PARAMETERS; + input_api->data = &post_api; + xine_list_append_content(this->post.input, input_api); + + input->xine_in.name = "audio"; + output->xine_out.name = "upmixed audio"; + this->post.xine_post.audio_input[0] = &port->new_port; + this->post.dispose = upmix_mono_dispose; + + return &this->post; +} + +static char *upmix_mono_get_identifier(post_class_t *class_gen) +{ + return "upmix_mono"; +} + +static char *upmix_mono_get_description(post_class_t *class_gen) +{ + return "converts Mono into Stereo"; +} + +static void upmix_mono_class_dispose(post_class_t *class_gen) +{ + free(class_gen); +} + +/* plugin class initialization function */ +void *upmix_mono_init_plugin(xine_t *xine, void *data) +{ + post_class_upmix_mono_t *class = (post_class_upmix_mono_t *)malloc(sizeof(post_class_upmix_mono_t)); + + if (!class) + return NULL; + + class->post_class.open_plugin = upmix_mono_open_plugin; + class->post_class.get_identifier = upmix_mono_get_identifier; + class->post_class.get_description = upmix_mono_get_description; + class->post_class.dispose = upmix_mono_class_dispose; + + class->xine = xine; + + return class; +} + |