VLC_ADD_PLUGINS([i420_yuy2 i422_yuy2 i420_ymga])
VLC_ADD_PLUGINS([aout_file linear_resampler bandlimited_resampler])
VLC_ADD_PLUGINS([float32_mixer spdif_mixer simple_channel_mixer])
- VLC_ADD_PLUGINS([headphone_channel_mixer normvol equalizer])
+ VLC_ADD_PLUGINS([dolby_surround_decoder headphone_channel_mixer normvol equalizer])
VLC_ADD_PLUGINS([fixed32tofloat32 float32tos16 float32tos8 float32tou16 float32tou8 a52tospdif dtstospdif s16tofloat32 s16tofloat32swab s8tofloat32 u8tofloat32 audio_format])
fi
* dmo: a DirectMediaObject decoder that uses DirectMedia to decode video (WMV3)
+ * dolby_surround_decoder: simple decoder for dolby surround encoded streams
+
* dshow: DirectShow access plugin for encoding cards under Windows
* dts: DTS basic parser/packetizer
SOURCES_trivial_channel_mixer = trivial.c
SOURCES_simple_channel_mixer = simple.c
SOURCES_headphone_channel_mixer = headphone.c
+SOURCES_dolby_surround_decoder = dolby.c
--- /dev/null
+/*****************************************************************************
+ * dolby.c : simple decoder for dolby surround encoded streams
+ *****************************************************************************
+ * Copyright (C) 2005 the VideoLAN team
+ * $Id: headphone.c 11664 2005-07-09 06:17:09Z courmisch $
+ *
+ * Authors: Boris Dorès <babal@via.ecp.fr>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <stdlib.h> /* malloc(), free() */
+#include <string.h>
+
+#include <vlc/vlc.h>
+#include "audio_output.h"
+#include "aout_internal.h"
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static int Create ( vlc_object_t * );
+static void Destroy ( vlc_object_t * );
+
+static void DoWork ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
+ aout_buffer_t * );
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin();
+ set_description( N_("Simple decoder for dolby surround encoded streams") );
+ set_shortname( _("Dolby surround decoder") );
+ set_category( CAT_INPUT );
+ set_subcategory( SUBCAT_INPUT_ACODEC );
+ set_capability( "audio filter", 5 );
+ set_callbacks( Create, Destroy );
+vlc_module_end();
+
+/*****************************************************************************
+ * Internal data structures
+ *****************************************************************************/
+struct aout_filter_sys_t
+{
+ int i_left;
+ int i_center;
+ int i_right;
+ int i_rear_left;
+ int i_rear_center;
+ int i_rear_right;
+};
+
+/* our internal channel order (WG-4 order) */
+static const uint32_t pi_channels[] =
+{ AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT,
+ AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, AOUT_CHAN_REARCENTER,
+ AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };
+
+/*****************************************************************************
+ * Create: allocate headphone downmixer
+ *****************************************************************************/
+static int Create( vlc_object_t *p_this )
+{
+ int i = 0;
+ int i_offset = 0;
+ aout_filter_t * p_filter = (aout_filter_t *)p_this;
+
+ /* Validate audio filter format */
+ if ( p_filter->input.i_original_channels
+ != (AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT|AOUT_CHAN_DOLBYSTEREO )
+ || aout_FormatNbChannels( &p_filter->output ) <= 2
+ || p_filter->output.i_physical_channels
+ != ( p_filter->output.i_original_channels & AOUT_CHAN_PHYSMASK )
+ || p_filter->input.i_physical_channels
+ != ( p_filter->input.i_original_channels & AOUT_CHAN_PHYSMASK ))
+ {
+ return VLC_EGENERIC;
+ }
+
+ if ( p_filter->input.i_rate != p_filter->output.i_rate )
+ {
+ return VLC_EGENERIC;
+ }
+
+ if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
+ || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
+ {
+ return VLC_EGENERIC;
+ }
+
+ /* Allocate the memory needed to store the module's structure */
+ p_filter->p_sys = malloc( sizeof(struct aout_filter_sys_t) );
+ if ( p_filter->p_sys == NULL )
+ {
+ msg_Err( p_filter, "Out of memory" );
+ return VLC_EGENERIC;
+ }
+ p_filter->p_sys->i_left = -1;
+ p_filter->p_sys->i_center = -1;
+ p_filter->p_sys->i_right = -1;
+ p_filter->p_sys->i_rear_left = -1;
+ p_filter->p_sys->i_rear_center = -1;
+ p_filter->p_sys->i_rear_right = -1;
+
+ while ( pi_channels[i] )
+ {
+ if ( p_filter->output.i_physical_channels & pi_channels[i] )
+ {
+ switch ( pi_channels[i] )
+ {
+ case AOUT_CHAN_LEFT:
+ p_filter->p_sys->i_left = i_offset;
+ break;
+ case AOUT_CHAN_CENTER:
+ p_filter->p_sys->i_center = i_offset;
+ break;
+ case AOUT_CHAN_RIGHT:
+ p_filter->p_sys->i_right = i_offset;
+ break;
+ case AOUT_CHAN_REARLEFT:
+ p_filter->p_sys->i_rear_left = i_offset;
+ break;
+ case AOUT_CHAN_REARCENTER:
+ p_filter->p_sys->i_rear_center = i_offset;
+ break;
+ case AOUT_CHAN_REARRIGHT:
+ p_filter->p_sys->i_rear_right = i_offset;
+ break;
+ }
+ ++i_offset;
+ }
+ ++i;
+ }
+
+ p_filter->pf_do_work = DoWork;
+ p_filter->b_in_place = 0;
+
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * Destroy: deallocate resources associated with headphone downmixer
+ *****************************************************************************/
+static void Destroy( vlc_object_t *p_this )
+{
+ aout_filter_t * p_filter = (aout_filter_t *)p_this;
+
+ if ( p_filter->p_sys != NULL )
+ {
+ free ( p_filter->p_sys );
+ p_filter->p_sys = NULL;
+ }
+}
+
+/*****************************************************************************
+ * DoWork: convert a buffer
+ *****************************************************************************/
+static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
+ aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
+{
+ float * p_in = (float*) p_in_buf->p_buffer;
+ float * p_out = (float*) p_out_buf->p_buffer;
+ size_t i_nb_samples = p_in_buf->i_nb_samples;
+ size_t i_nb_channels = aout_FormatNbChannels( &p_filter->output );
+
+ p_out_buf->i_nb_samples = i_nb_samples;
+ p_out_buf->i_nb_bytes = sizeof(float) * i_nb_samples
+ * aout_FormatNbChannels( &p_filter->output );
+ memset ( p_out , 0 , p_out_buf->i_nb_bytes );
+
+ if ( p_filter->p_sys != NULL )
+ {
+ struct aout_filter_sys_t * p_sys = p_filter->p_sys;
+ size_t i_nb_rear = 0;
+ size_t i;
+
+ if ( p_sys->i_rear_left >= 0 )
+ {
+ ++i_nb_rear;
+ }
+ if ( p_sys->i_rear_center >= 0 )
+ {
+ ++i_nb_rear;
+ }
+ if ( p_sys->i_rear_right >= 0 )
+ {
+ ++i_nb_rear;
+ }
+
+ for ( i = 0; i < i_nb_samples; ++i )
+ {
+ float f_left = p_in[ i * 2 ];
+ float f_right = p_in[ i * 2 + 1 ];
+ float f_rear = ( f_left - f_right ) / i_nb_rear;
+
+ if ( p_sys->i_center >= 0 )
+ {
+ float f_center = f_left + f_right;
+ f_left -= f_center / 2;
+ f_right -= f_center / 2;
+
+ p_out[ i * i_nb_channels + p_sys->i_center ] = f_center;
+ }
+
+ if ( p_sys->i_left >= 0 )
+ {
+ p_out[ i * i_nb_channels + p_sys->i_left ] = f_left;
+ }
+ if ( p_sys->i_right >= 0 )
+ {
+ p_out[ i * i_nb_channels + p_sys->i_right ] = f_right;
+ }
+ if ( p_sys->i_rear_left >= 0 )
+ {
+ p_out[ i * i_nb_channels + p_sys->i_rear_left ] = f_rear;
+ }
+ if ( p_sys->i_rear_center >= 0 )
+ {
+ p_out[ i * i_nb_channels + p_sys->i_rear_center ] = f_rear;
+ }
+ if ( p_sys->i_rear_right >= 0 )
+ {
+ p_out[ i * i_nb_channels + p_sys->i_rear_right ] = f_rear;
+ }
+ }
+ }
+}
* headphone.c : headphone virtual spatialization channel mixer module
* -> gives the feeling of a real room with a simple headphone
*****************************************************************************
- * Copyright (C) 2002 the VideoLAN team
+ * Copyright (C) 2002-2005 the VideoLAN team
* $Id$
*
* Authors: Boris Dorès <babal@via.ecp.fr>
*****************************************************************************/
#define MODULE_DESCRIPTION N_ ( \
"This effect gives you the feeling that you are standing in a room " \
- "with a complete 5.1 speaker set when using only a headphone, " \
+ "with a complete 7.1 speaker set when using only a headphone, " \
"providing a more realistic sound experience. It should also be " \
"more comfortable and less tiring when listening to music for " \
"long periods of time.\nIt works with any source format from mono " \
- "to 5.1.")
+ "to 7.1.")
#define HEADPHONE_DIM_TEXT N_("Characteristic dimension")
#define HEADPHONE_DIM_LONGTEXT N_( \
/* Number of elementary operations */
p_data->i_nb_atomic_operations = i_nb_channels * 2;
+ if ( i_physical_channels & AOUT_CHAN_CENTER )
+ {
+ p_data->i_nb_atomic_operations += 2;
+ }
p_data->p_atomic_operations = malloc ( sizeof(struct atomic_operation_t)
* p_data->i_nb_atomic_operations );
if ( p_data->p_atomic_operations == NULL )
i_next_atomic_operation += 2;
i_source_channel_offset++;
}
- if ( i_physical_channels & AOUT_CHAN_REARLEFT )
+ if ( i_physical_channels & AOUT_CHAN_MIDDLELEFT )
{
ComputeChannelOperations ( p_data , i_rate
, i_next_atomic_operation , i_source_channel_offset
- , -d_x , d_z_rear , 1.5 / i_nb_channels );
+ , -d_x , 0 , 1.5 / i_nb_channels );
i_next_atomic_operation += 2;
i_source_channel_offset++;
}
- if ( i_physical_channels & AOUT_CHAN_REARRIGHT )
+ if ( i_physical_channels & AOUT_CHAN_MIDDLERIGHT )
{
ComputeChannelOperations ( p_data , i_rate
, i_next_atomic_operation , i_source_channel_offset
- , d_x , d_z_rear , 1.5 / i_nb_channels );
+ , d_x , 0 , 1.5 / i_nb_channels );
i_next_atomic_operation += 2;
i_source_channel_offset++;
}
- if ( i_physical_channels & AOUT_CHAN_REARCENTER )
+ if ( i_physical_channels & AOUT_CHAN_REARLEFT )
{
ComputeChannelOperations ( p_data , i_rate
, i_next_atomic_operation , i_source_channel_offset
- , 0 , -d_z , 1.5 / i_nb_channels );
+ , -d_x , d_z_rear , 1.5 / i_nb_channels );
i_next_atomic_operation += 2;
i_source_channel_offset++;
}
- if ( i_physical_channels & AOUT_CHAN_CENTER )
+ if ( i_physical_channels & AOUT_CHAN_REARRIGHT )
{
ComputeChannelOperations ( p_data , i_rate
, i_next_atomic_operation , i_source_channel_offset
- , 0 , d_z , 1.5 / i_nb_channels );
+ , d_x , d_z_rear , 1.5 / i_nb_channels );
i_next_atomic_operation += 2;
i_source_channel_offset++;
}
- if ( i_physical_channels & AOUT_CHAN_LFE )
+ if ( i_physical_channels & AOUT_CHAN_REARCENTER )
{
ComputeChannelOperations ( p_data , i_rate
, i_next_atomic_operation , i_source_channel_offset
- , 0 , d_z_rear , 5.0 / i_nb_channels );
+ , 0 , -d_z , 1.5 / i_nb_channels );
i_next_atomic_operation += 2;
i_source_channel_offset++;
}
- if ( i_physical_channels & AOUT_CHAN_MIDDLELEFT )
+ if ( i_physical_channels & AOUT_CHAN_CENTER )
{
+ /* having two center channels increases the spatialization effect */
ComputeChannelOperations ( p_data , i_rate
, i_next_atomic_operation , i_source_channel_offset
- , -d_x , 0 , 1.5 / i_nb_channels );
+ , d_x / 5.0 , d_z , 0.75 / i_nb_channels );
+ i_next_atomic_operation += 2;
+ ComputeChannelOperations ( p_data , i_rate
+ , i_next_atomic_operation , i_source_channel_offset
+ , -d_x / 5.0 , d_z , 0.75 / i_nb_channels );
i_next_atomic_operation += 2;
i_source_channel_offset++;
}
- if ( i_physical_channels & AOUT_CHAN_MIDDLERIGHT )
+ if ( i_physical_channels & AOUT_CHAN_LFE )
{
ComputeChannelOperations ( p_data , i_rate
, i_next_atomic_operation , i_source_channel_offset
- , d_x , 0 , 1.5 / i_nb_channels );
+ , 0 , d_z_rear , 5.0 / i_nb_channels );
i_next_atomic_operation += 2;
i_source_channel_offset++;
}
static int Create( vlc_object_t *p_this )
{
aout_filter_t * p_filter = (aout_filter_t *)p_this;
+ vlc_bool_t b_fit = VLC_TRUE;
+
+ /* Activate this filter only with stereo devices */
+ if ( p_filter->output.i_physical_channels != (AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT)
+ || p_filter->output.i_physical_channels
+ != ( p_filter->output.i_original_channels & AOUT_CHAN_PHYSMASK )
+ || p_filter->input.i_physical_channels
+ != ( p_filter->input.i_original_channels & AOUT_CHAN_PHYSMASK ) )
+ {
+ msg_Dbg( p_filter, "Filter discarded (incompatible format)" );
+ return VLC_EGENERIC;
+ }
- if ( p_filter->output.i_physical_channels != ( AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT )
- || p_filter->input.i_format != p_filter->output.i_format
- || p_filter->input.i_rate != p_filter->output.i_rate
- || (p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
- && p_filter->input.i_format != VLC_FOURCC('f','i','3','2')) )
+ /* Request a specific format if not already compatible */
+ if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
+ || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
{
- msg_Dbg( p_filter, "Filter discarded (invalid format)" );
- return -1;
+ b_fit = VLC_FALSE;
+ p_filter->input.i_format = VLC_FOURCC('f','l','3','2');
+ p_filter->output.i_format = VLC_FOURCC('f','l','3','2');
+ }
+ if ( p_filter->input.i_rate != p_filter->output.i_rate )
+ {
+ b_fit = VLC_FALSE;
+ p_filter->input.i_rate = p_filter->output.i_rate;
+ }
+ if ( p_filter->input.i_physical_channels == (AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT)
+ && ( p_filter->input.i_original_channels & AOUT_CHAN_DOLBYSTEREO ) )
+ {
+ b_fit = VLC_FALSE;
+ p_filter->input.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
+ AOUT_CHAN_CENTER |
+ AOUT_CHAN_REARLEFT |
+ AOUT_CHAN_REARRIGHT;
+ p_filter->input.i_original_channels = p_filter->input.i_physical_channels;
+ }
+ if ( ! b_fit )
+ {
+ msg_Dbg( p_filter, "Requesting specific format" );
+ return VLC_EGENERIC;
}
/* Allocate the memory needed to store the module's structure */
p_filter->p_sys = malloc( sizeof(struct aout_filter_sys_t) );
if ( p_filter->p_sys == NULL )
{
- msg_Err( p_filter, "out of memory" );
- return -1;
+ msg_Err( p_filter, "Out of memory" );
+ return VLC_EGENERIC;
}
p_filter->p_sys->i_overflow_buffer_size = 0;
p_filter->p_sys->p_overflow_buffer = NULL;
, p_filter->input.i_physical_channels
, p_filter->input.i_rate ) < 0 )
{
- return -1;
+ return VLC_EGENERIC;
}
p_filter->pf_do_work = DoWork;
p_filter->b_in_place = 0;
- return 0;
+ return VLC_SUCCESS;
}
/*****************************************************************************
{
aout_filter_t *p_filter = (aout_filter_t *)p_this;
aout_filter_sys_t *p_sys;
+ vlc_bool_t b_fit = VLC_TRUE;
if( p_filter->input.i_format != VLC_FOURCC('f','l','3','2' ) ||
p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
{
+ b_fit = VLC_FALSE;
+ p_filter->input.i_format = VLC_FOURCC('f','l','3','2');
+ p_filter->output.i_format = VLC_FOURCC('f','l','3','2');
msg_Warn( p_filter, "Bad input or output format" );
- return VLC_EGENERIC;
}
if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
{
+ b_fit = VLC_FALSE;
+ memcpy( &p_filter->output, &p_filter->input,
+ sizeof(audio_sample_format_t) );
msg_Warn( p_filter, "input and output formats are not similar" );
+ }
+
+ if ( ! b_fit )
+ {
return VLC_EGENERIC;
}
static int Open( vlc_object_t *p_this )
{
aout_filter_t *p_filter = (aout_filter_t*)p_this;
+ vlc_bool_t b_fit = VLC_TRUE;
int i_channels;
aout_filter_sys_t *p_sys = p_filter->p_sys =
malloc( sizeof( aout_filter_sys_t ) );
if( p_filter->input.i_format != VLC_FOURCC('f','l','3','2' ) ||
p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
{
- msg_Warn( p_filter, "Bad input or output format" );
- return VLC_EGENERIC;
+ b_fit = VLC_FALSE;
+ p_filter->input.i_format = VLC_FOURCC('f','l','3','2');
+ p_filter->output.i_format = VLC_FOURCC('f','l','3','2');
+ msg_Warn( p_filter, "Bad input or output format" );
}
if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
{
+ b_fit = VLC_FALSE;
+ memcpy( &p_filter->output, &p_filter->input,
+ sizeof(audio_sample_format_t) );
msg_Warn( p_filter, "input and output formats are not similar" );
+ }
+
+ if ( ! b_fit )
+ {
return VLC_EGENERIC;
}
/* en-/disable headphone virtualisation */
if ([o_ckb_hdphnVirt state] == NSOnState)
{
- [self changeAFiltersString: "headphone" onOrOff: VLC_TRUE ];
+ [self changeAFiltersString: "headphone_channel_mixer" onOrOff: VLC_TRUE ];
}else{
- [self changeAFiltersString: "headphone" onOrOff: VLC_FALSE ];
+ [self changeAFiltersString: "headphone_channel_mixer" onOrOff: VLC_FALSE ];
}
}
{
aout_instance_t *p_aout= (aout_instance_t *)vlc_object_find(p_intf,
VLC_OBJECT_AOUT, FIND_ANYWHERE);
- ChangeFiltersString( p_intf , p_aout, "headphone",
+ ChangeFiltersString( p_intf , p_aout, "headphone_channel_mixer",
event.IsChecked() ? VLC_TRUE : VLC_FALSE );
if( p_aout != NULL )
vlc_object_release( p_aout );
return 2;
}
+static void ReleaseFilter( aout_filter_t * p_filter )
+{
+ module_Unneed( p_filter, p_filter->p_module );
+ vlc_object_detach( p_filter );
+ vlc_object_destroy( p_filter );
+}
+
/*****************************************************************************
* aout_FiltersCreatePipeline: create a filters pipeline to transform a sample
* format to another
*****************************************************************************
- * TODO : allow the user to add/remove specific filters
+ * pi_nb_filters must be initialized before calling this function
*****************************************************************************/
int aout_FiltersCreatePipeline( aout_instance_t * p_aout,
- aout_filter_t ** pp_filters,
+ aout_filter_t ** pp_filters_start,
int * pi_nb_filters,
const audio_sample_format_t * p_input_format,
const audio_sample_format_t * p_output_format )
{
+ aout_filter_t** pp_filters = pp_filters_start + *pi_nb_filters;
audio_sample_format_t temp_format;
int i_nb_conversions;
if ( AOUT_FMTS_IDENTICAL( p_input_format, p_output_format ) )
{
msg_Dbg( p_aout, "no need for any filter" );
- *pi_nb_filters = 0;
return 0;
}
aout_FormatsPrint( p_aout, "filter(s)", p_input_format, p_output_format );
+ if( *pi_nb_filters + 1 > AOUT_MAX_FILTERS )
+ {
+ msg_Err( p_aout, "max filter reached (%d)", AOUT_MAX_FILTERS );
+ return -1;
+ }
+
/* Try to find a filter to do the whole conversion. */
pp_filters[0] = FindFilter( p_aout, p_input_format, p_output_format );
if ( pp_filters[0] != NULL )
{
msg_Dbg( p_aout, "found a filter for the whole conversion" );
- *pi_nb_filters = 1;
+ ++*pi_nb_filters;
return 0;
}
/* We have the first stage of the conversion. Find a filter for
* the rest. */
+ if( *pi_nb_filters + 2 > AOUT_MAX_FILTERS )
+ {
+ ReleaseFilter( pp_filters[0] );
+ msg_Err( p_aout, "max filter reached (%d)", AOUT_MAX_FILTERS );
+ return -1;
+ }
pp_filters[1] = FindFilter( p_aout, &pp_filters[0]->output,
p_output_format );
if ( pp_filters[1] == NULL )
p_output_format, &temp_format );
if ( !i_nb_conversions )
{
- vlc_object_detach( pp_filters[0] );
- vlc_object_destroy( pp_filters[0] );
+ ReleaseFilter( pp_filters[0] );
msg_Err( p_aout,
"couldn't find a filter for the second part of the conversion" );
+ return -1;
+ }
+ if( *pi_nb_filters + 3 > AOUT_MAX_FILTERS )
+ {
+ ReleaseFilter( pp_filters[0] );
+ msg_Err( p_aout, "max filter reached (%d)", AOUT_MAX_FILTERS );
+ return -1;
}
pp_filters[1] = FindFilter( p_aout, &pp_filters[0]->output,
&temp_format );
if ( pp_filters[1] == NULL || pp_filters[2] == NULL )
{
- vlc_object_detach( pp_filters[0] );
- vlc_object_destroy( pp_filters[0] );
+ ReleaseFilter( pp_filters[0] );
if ( pp_filters[1] != NULL )
{
- vlc_object_detach( pp_filters[1] );
- vlc_object_destroy( pp_filters[1] );
+ ReleaseFilter( pp_filters[1] );
}
if ( pp_filters[2] != NULL )
{
- vlc_object_detach( pp_filters[2] );
- vlc_object_destroy( pp_filters[2] );
+ ReleaseFilter( pp_filters[2] );
}
msg_Err( p_aout,
"couldn't find filters for the second part of the conversion" );
+ return -1;
}
- *pi_nb_filters = 3;
+ *pi_nb_filters += 3;
+ msg_Dbg( p_aout, "found 3 filters for the whole conversion" );
}
else
{
- *pi_nb_filters = 2;
+ *pi_nb_filters += 2;
+ msg_Dbg( p_aout, "found 2 filters for the whole conversion" );
}
- /* We have enough filters. */
- msg_Dbg( p_aout, "found %d filters for the whole conversion",
- *pi_nb_filters );
return 0;
}
#include "audio_output.h"
#include "aout_internal.h"
+static void inputFailure( aout_instance_t *, aout_input_t *, char * );
static int VisualizationCallback( vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void * );
static int EqualizerCallback( vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void * );
-static aout_filter_t * allocateUserChannelMixer( aout_instance_t *,
- audio_sample_format_t *,
- audio_sample_format_t * );
/*****************************************************************************
* aout_InputNew : allocate a new input and rework the filter pipeline
*****************************************************************************/
int aout_InputNew( aout_instance_t * p_aout, aout_input_t * p_input )
{
- audio_sample_format_t user_filter_format;
- audio_sample_format_t intermediate_format;/* input of resampler */
+ audio_sample_format_t chain_input_format;
+ audio_sample_format_t chain_output_format;
vlc_value_t val, text;
char * psz_filters, *psz_visual;
- aout_filter_t * p_user_channel_mixer;
aout_FormatPrint( p_aout, "input", &p_input->input );
+ p_input->i_nb_filters = 0;
+
/* Prepare FIFO. */
aout_FifoInit( p_aout, &p_input->fifo, p_aout->mixer.mixer.i_rate );
p_input->p_first_byte_to_mix = NULL;
/* Prepare format structure */
- memcpy( &intermediate_format, &p_aout->mixer.mixer,
+ memcpy( &chain_input_format, &p_input->input,
sizeof(audio_sample_format_t) );
- intermediate_format.i_rate = p_input->input.i_rate;
-
- /* Try to use the channel mixer chosen by the user */
- memcpy ( &user_filter_format, &intermediate_format,
- sizeof(audio_sample_format_t) );
- user_filter_format.i_physical_channels = p_input->input.i_physical_channels;
- user_filter_format.i_original_channels = p_input->input.i_original_channels;
- user_filter_format.i_bytes_per_frame = user_filter_format.i_bytes_per_frame
- * aout_FormatNbChannels( &user_filter_format )
- / aout_FormatNbChannels( &intermediate_format );
- p_user_channel_mixer = allocateUserChannelMixer( p_aout, &user_filter_format,
- &intermediate_format );
- /* If it failed, let the main pipeline do channel mixing */
- if ( ! p_user_channel_mixer )
- {
- memcpy ( &user_filter_format, &intermediate_format,
- sizeof(audio_sample_format_t) );
- }
-
- /* Create filters. */
- if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters,
- &p_input->i_nb_filters,
- &p_input->input,
- &user_filter_format
- ) < 0 )
- {
- msg_Err( p_aout, "couldn't set an input pipeline" );
-
- aout_FifoDestroy( p_aout, &p_input->fifo );
- p_input->b_error = 1;
- return -1;
- }
+ memcpy( &chain_output_format, &p_aout->mixer.mixer,
+ sizeof(audio_sample_format_t) );
+ chain_output_format.i_rate = p_input->input.i_rate;
+ aout_FormatPrepare( &chain_output_format );
/* Now add user filters */
if( var_Type( p_aout, "visual" ) == 0 )
psz_filters = strdup( psz_visual );
}
+ /* parse user filter list */
if( psz_filters && *psz_filters )
{
char *psz_parser = psz_filters;
char *psz_next;
while( psz_parser && *psz_parser )
{
- aout_filter_t * p_filter;
+ aout_filter_t * p_filter = NULL;
if( p_input->i_nb_filters >= AOUT_MAX_FILTERS )
{
break;
}
- msg_Dbg( p_aout, "user filter \"%s\"", psz_parser );
-
/* Create a VLC object */
p_filter = vlc_object_create( p_aout, sizeof(aout_filter_t) );
if( p_filter == NULL )
}
vlc_object_attach( p_filter , p_aout );
- memcpy( &p_filter->input, &user_filter_format,
+
+ /* request format */
+ memcpy( &p_filter->input, &chain_input_format,
sizeof(audio_sample_format_t) );
- memcpy( &p_filter->output, &user_filter_format,
+ memcpy( &p_filter->output, &chain_output_format,
sizeof(audio_sample_format_t) );
- p_filter->p_module =
- module_Need( p_filter,"audio filter", psz_parser, VLC_FALSE );
+ /* try to find the requested filter */
+ p_filter->p_module = module_Need( p_filter, "audio filter",
+ psz_parser, VLC_TRUE );
+
+ if ( p_filter->p_module == NULL )
+ {
+ /* if the filter requested a special format, retry */
+ if ( !( AOUT_FMTS_IDENTICAL( &p_filter->input,
+ &chain_input_format )
+ && AOUT_FMTS_IDENTICAL( &p_filter->output,
+ &chain_output_format ) ) )
+ {
+ aout_FormatPrepare( &p_filter->input );
+ aout_FormatPrepare( &p_filter->output );
+ p_filter->p_module = module_Need( p_filter, "audio filter",
+ psz_parser, VLC_TRUE );
+ }
+ /* try visual filters */
+ else
+ {
+ memcpy( &p_filter->input, &chain_output_format,
+ sizeof(audio_sample_format_t) );
+ memcpy( &p_filter->output, &chain_output_format,
+ sizeof(audio_sample_format_t) );
+ p_filter->p_module = module_Need( p_filter, "visualization",
+ psz_parser, VLC_TRUE );
+ }
+ }
+
+ /* failure */
+ if ( p_filter->p_module == NULL )
+ {
+ msg_Err( p_aout, "cannot add user filter %s (skipped)",
+ psz_parser );
+
+ vlc_object_detach( p_filter );
+ vlc_object_destroy( p_filter );
+
+ psz_parser = psz_next;
+ continue;
+ }
- if( p_filter->p_module== NULL )
+ /* complete the filter chain if necessary */
+ if ( !AOUT_FMTS_IDENTICAL( &chain_input_format, &p_filter->input ) )
{
- p_filter->p_module =
- module_Need( p_filter,"visualization", psz_parser,
- VLC_FALSE );
- if( p_filter->p_module == NULL )
+ if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters,
+ &p_input->i_nb_filters,
+ &chain_input_format,
+ &p_filter->input ) < 0 )
{
msg_Err( p_aout, "cannot add user filter %s (skipped)",
psz_parser );
+ module_Unneed( p_filter, p_filter->p_module );
vlc_object_detach( p_filter );
vlc_object_destroy( p_filter );
+
psz_parser = psz_next;
continue;
}
}
- p_filter->b_continuity = VLC_FALSE;
+ /* success */
+ p_filter->b_continuity = VLC_FALSE;
p_input->pp_filters[p_input->i_nb_filters++] = p_filter;
+ memcpy( &chain_input_format, &p_filter->output,
+ sizeof( audio_sample_format_t ) );
/* next filter if any */
psz_parser = psz_next;
if( psz_filters ) free( psz_filters );
if( psz_visual ) free( psz_visual );
- /* Attach the user channel mixer */
- if ( p_user_channel_mixer )
+ /* complete the filter chain if necessary */
+ if ( !AOUT_FMTS_IDENTICAL( &chain_input_format, &chain_output_format ) )
{
- p_input->pp_filters[p_input->i_nb_filters++] = p_user_channel_mixer;
+ if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters,
+ &p_input->i_nb_filters,
+ &chain_input_format,
+ &chain_output_format ) < 0 )
+ {
+ inputFailure( p_aout, p_input, "couldn't set an input pipeline" );
+ return -1;
+ }
}
/* Prepare hints for the buffer allocator. */
p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
p_input->input_alloc.i_bytes_per_sec = -1;
+ /* Create resamplers. */
if ( AOUT_FMT_NON_LINEAR( &p_aout->mixer.mixer ) )
{
p_input->i_nb_resamplers = 0;
}
else
{
- /* Create resamplers. */
- intermediate_format.i_rate = (__MAX(p_input->input.i_rate,
+ chain_output_format.i_rate = (__MAX(p_input->input.i_rate,
p_aout->mixer.mixer.i_rate)
* (100 + AOUT_MAX_RESAMPLING)) / 100;
- if ( intermediate_format.i_rate == p_aout->mixer.mixer.i_rate )
+ if ( chain_output_format.i_rate == p_aout->mixer.mixer.i_rate )
{
/* Just in case... */
- intermediate_format.i_rate++;
+ chain_output_format.i_rate++;
}
+ p_input->i_nb_resamplers = 0;
if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_resamplers,
&p_input->i_nb_resamplers,
- &intermediate_format,
+ &chain_output_format,
&p_aout->mixer.mixer ) < 0 )
{
- msg_Err( p_aout, "couldn't set a resampler pipeline" );
-
- aout_FiltersDestroyPipeline( p_aout, p_input->pp_filters,
- p_input->i_nb_filters );
- aout_FifoDestroy( p_aout, &p_input->fifo );
- var_Destroy( p_aout, "visual" );
- p_input->b_error = 1;
-
+ inputFailure( p_aout, p_input, "couldn't set a resampler pipeline");
return -1;
}
aout_FiltersHintBuffers( p_aout, p_input->pp_resamplers,
p_input->i_nb_resamplers,
&p_input->input_alloc );
+ p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
/* Setup the initial rate of the resampler */
p_input->pp_resamplers[0]->input.i_rate = p_input->input.i_rate;
}
p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
- p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
aout_FiltersHintBuffers( p_aout, p_input->pp_filters,
p_input->i_nb_filters,
&p_input->input_alloc );
+ p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
/* i_bytes_per_sec is still == -1 if no filters */
p_input->input_alloc.i_bytes_per_sec = __MAX(
(int)(p_input->input.i_bytes_per_frame
* p_input->input.i_rate
/ p_input->input.i_frame_length) );
- /* Allocate in the heap, it is more convenient for the decoder. */
- p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
+ /* Success */
p_input->b_error = VLC_FALSE;
p_input->b_restart = VLC_FALSE;
aout_FiltersDestroyPipeline( p_aout, p_input->pp_filters,
p_input->i_nb_filters );
+ p_input->i_nb_filters = 0;
aout_FiltersDestroyPipeline( p_aout, p_input->pp_resamplers,
p_input->i_nb_resamplers );
+ p_input->i_nb_resamplers = 0;
aout_FifoDestroy( p_aout, &p_input->fifo );
return 0;
return 0;
}
-static int ChangeFiltersString( aout_instance_t * p_aout,
+/*****************************************************************************
+ * static functions
+ *****************************************************************************/
+
+static void inputFailure( aout_instance_t * p_aout, aout_input_t * p_input,
+ char * psz_error_message )
+{
+ /* error message */
+ msg_Err( p_aout, "couldn't set an input pipeline" );
+
+ /* clean up */
+ aout_FiltersDestroyPipeline( p_aout, p_input->pp_filters,
+ p_input->i_nb_filters );
+ aout_FiltersDestroyPipeline( p_aout, p_input->pp_resamplers,
+ p_input->i_nb_resamplers );
+ aout_FifoDestroy( p_aout, &p_input->fifo );
+ var_Destroy( p_aout, "visual" );
+ var_Destroy( p_aout, "equalizer" );
+ var_Destroy( p_aout, "audio-filter" );
+ var_Destroy( p_aout, "audio-visual" );
+
+ /* error flag */
+ p_input->b_error = 1;
+}
+
+static int ChangeFiltersString( aout_instance_t * p_aout, char* psz_variable,
char *psz_name, vlc_bool_t b_add )
{
vlc_value_t val;
char *psz_parser;
- var_Get( p_aout, "audio-filter", &val );
+ var_Get( p_aout, psz_variable, &val );
if( !val.psz_string ) val.psz_string = strdup("");
}
}
- var_Set( p_aout, "audio-filter", val );
+ var_Set( p_aout, psz_variable, val );
free( val.psz_string );
return 1;
}
if( !psz_mode || !*psz_mode )
{
- ChangeFiltersString( p_aout, "goom", VLC_FALSE );
- ChangeFiltersString( p_aout, "visual", VLC_FALSE );
- ChangeFiltersString( p_aout, "galaktos", VLC_FALSE );
+ ChangeFiltersString( p_aout, "audio-visual", "goom", VLC_FALSE );
+ ChangeFiltersString( p_aout, "audio-visual", "visual", VLC_FALSE );
+ ChangeFiltersString( p_aout, "audio-visual", "galaktos", VLC_FALSE );
}
else
{
if( !strcmp( "goom", psz_mode ) )
{
- ChangeFiltersString( p_aout, "visual", VLC_FALSE );
- ChangeFiltersString( p_aout, "goom", VLC_TRUE );
- ChangeFiltersString( p_aout, "galaktos", VLC_FALSE );
+ ChangeFiltersString( p_aout, "audio-visual", "visual", VLC_FALSE );
+ ChangeFiltersString( p_aout, "audio-visual", "goom", VLC_TRUE );
+ ChangeFiltersString( p_aout, "audio-visual", "galaktos", VLC_FALSE);
}
else if( !strcmp( "galaktos", psz_mode ) )
{
- ChangeFiltersString( p_aout, "visual", VLC_FALSE );
- ChangeFiltersString( p_aout, "goom", VLC_FALSE );
- ChangeFiltersString( p_aout, "galaktos", VLC_TRUE );
+ ChangeFiltersString( p_aout, "audio-visual", "visual", VLC_FALSE );
+ ChangeFiltersString( p_aout, "audio-visual", "goom", VLC_FALSE );
+ ChangeFiltersString( p_aout, "audio-visual", "galaktos", VLC_TRUE );
}
else
{
var_Create( p_aout, "effect-list", VLC_VAR_STRING );
var_Set( p_aout, "effect-list", val );
- ChangeFiltersString( p_aout, "goom", VLC_FALSE );
- ChangeFiltersString( p_aout, "visual", VLC_TRUE );
- ChangeFiltersString( p_aout, "galaktos", VLC_FALSE );
+ ChangeFiltersString( p_aout, "audio-visual", "goom", VLC_FALSE );
+ ChangeFiltersString( p_aout, "audio-visual", "visual", VLC_TRUE );
+ ChangeFiltersString( p_aout, "audio-visual", "galaktos", VLC_FALSE);
}
}
if( !psz_mode || !*psz_mode )
{
- i_ret = ChangeFiltersString( p_aout, "equalizer", VLC_FALSE );
+ i_ret = ChangeFiltersString( p_aout, "audio-filter", "equalizer",
+ VLC_FALSE );
}
else
{
val.psz_string = psz_mode;
var_Create( p_aout, "equalizer-preset", VLC_VAR_STRING );
var_Set( p_aout, "equalizer-preset", val );
- i_ret = ChangeFiltersString( p_aout, "equalizer", VLC_TRUE );
+ i_ret = ChangeFiltersString( p_aout, "audio-filter", "equalizer",
+ VLC_TRUE );
}
return VLC_SUCCESS;
}
-
-static aout_filter_t * allocateUserChannelMixer( aout_instance_t * p_aout,
- audio_sample_format_t * p_input_format,
- audio_sample_format_t * p_output_format )
-{
- aout_filter_t * p_channel_mixer;
-
- /* Retreive user preferred channel mixer */
- char * psz_name = config_GetPsz( p_aout, "audio-channel-mixer" );
-
- /* Not specified => let the main pipeline do the mixing */
- if ( ! psz_name ) return NULL;
-
- /* Debug information */
- aout_FormatsPrint( p_aout, "channel mixer", p_input_format,
- p_output_format );
-
- /* Create a VLC object */
- p_channel_mixer = vlc_object_create( p_aout, sizeof(aout_filter_t) );
- if( p_channel_mixer == NULL )
- {
- msg_Err( p_aout, "cannot add user channel mixer %s", psz_name );
- return NULL;
- }
- vlc_object_attach( p_channel_mixer , p_aout );
-
- /* Attach the suitable module */
- memcpy( &p_channel_mixer->input, p_input_format,
- sizeof(audio_sample_format_t) );
- memcpy( &p_channel_mixer->output, p_output_format,
- sizeof(audio_sample_format_t) );
- p_channel_mixer->p_module =
- module_Need( p_channel_mixer,"audio filter", psz_name, VLC_TRUE );
- if( p_channel_mixer->p_module== NULL )
- {
- msg_Err( p_aout, "cannot add user channel mixer %s", psz_name );
- vlc_object_detach( p_channel_mixer );
- vlc_object_destroy( p_channel_mixer );
- return NULL;
- }
- p_channel_mixer->b_continuity = VLC_FALSE;
-
- /* Ok */
- return p_channel_mixer;
-}
aout_FormatPrint( p_aout, "mixer", &p_aout->output.output );
/* Create filters. */
+ p_aout->output.i_nb_filters = 0;
if ( aout_FiltersCreatePipeline( p_aout, p_aout->output.pp_filters,
&p_aout->output.i_nb_filters,
&p_aout->mixer.mixer,
if( p_sys->p_aout_input == NULL )
{
+ audio_sample_format_t format;
+ int i_force_dolby = config_GetInt( p_dec, "force-dolby-surround" );
+
p_dec->fmt_out.audio.i_format = p_dec->fmt_out.i_codec;
p_sys->audio = p_dec->fmt_out.audio;
+
+ memcpy( &format, &p_sys->audio, sizeof( audio_sample_format_t ) );
+ if ( i_force_dolby && (format.i_original_channels&AOUT_CHAN_PHYSMASK)
+ == (AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT) )
+ {
+ if ( i_force_dolby > 0 )
+ {
+ format.i_original_channels = format.i_original_channels |
+ AOUT_CHAN_DOLBYSTEREO;
+ }
+ else
+ {
+ format.i_original_channels = format.i_original_channels &
+ ~AOUT_CHAN_DOLBYSTEREO;
+ }
+ }
+
p_sys->p_aout_input =
- aout_DecNew( p_dec, &p_sys->p_aout, &p_sys->audio );
+ aout_DecNew( p_dec, &p_sys->p_aout, &format );
if( p_sys->p_aout_input == NULL )
{
msg_Err( p_dec, "failed to create audio output" );
"This option allows you to use the S/PDIF audio output by default when " \
"your hardware supports it as well as the audio stream being played.")
+#define FORCE_DOLBY_TEXT N_("Force detection of Dolby Surround")
+#define FORCE_DOLBY_LONGTEXT N_( \
+ "Use this when you know your stream is or is not encoded with Dolby Surround " \
+ "but fails to be detected as such." )
+static int pi_force_dolby_values[] = { 0, 1, -1 };
+static char *ppsz_force_dolby_descriptions[] = { N_("Auto"), N_("On"), N_("Off") };
+
+
#define AUDIO_FILTER_TEXT N_("Audio filters")
#define AUDIO_FILTER_LONGTEXT N_( \
"This allows you to add audio post processing filters, to modify " \
"This allows you to add visualization modules " \
"(spectrum analyzer, etc.).")
-#define AUDIO_CHANNEL_MIXER N_("Channel mixer")
-#define AUDIO_CHANNEL_MIXER_LONGTEXT N_( \
- "This allows you to choose a specific audio channel mixer. For " \
- "instance, you can use the \"headphone\" mixer that gives 5.1 feeling " \
- "with a headphone.")
-
#define VOUT_CAT_LONGTEXT N_( \
"These options allow you to modify the behavior of the video output " \
"subsystem. You can for example enable video filters (deinterlacing, " \
AOUT_RESAMP_LONGTEXT, VLC_TRUE );
#endif
add_bool( "spdif", 0, NULL, SPDIF_TEXT, SPDIF_LONGTEXT, VLC_FALSE );
+ add_integer( "force-dolby-surround", 0, NULL, FORCE_DOLBY_TEXT,
+ FORCE_DOLBY_LONGTEXT, VLC_FALSE );
+ change_integer_list( pi_force_dolby_values, ppsz_force_dolby_descriptions, 0 );
add_integer( "audio-desync", 0, NULL, DESYNC_TEXT,
DESYNC_LONGTEXT, VLC_TRUE );
set_subcategory( SUBCAT_AUDIO_AOUT );
add_category_hint( N_("Miscellaneous"), MISC_CAT_LONGTEXT, VLC_TRUE );
add_module( "memcpy", "memcpy", NULL, NULL, MEMCPY_TEXT,
MEMCPY_LONGTEXT, VLC_TRUE );
- add_module( "audio-channel-mixer", "audio mixer", NULL, NULL,
- AUDIO_CHANNEL_MIXER, AUDIO_CHANNEL_MIXER_LONGTEXT, VLC_TRUE );
change_short('A');
set_section( N_("Plugins" ), NULL );
%dir %_libdir/vlc/audio_filter
%_libdir/vlc/audio_filter/libbandlimited_resampler_plugin.so
+%_libdir/vlc/audio_filter/libdolby_surround_decoder_plugin.so
%_libdir/vlc/audio_filter/libdtstospdif_plugin.so
%_libdir/vlc/audio_filter/libfixed32tofloat32_plugin.so
%_libdir/vlc/audio_filter/libfixed32tos16_plugin.so