- the creation of the audio filter pipeline when specifying user audio
authorBoris Dorès <babal@videolan.org>
Sun, 25 Sep 2005 16:49:40 +0000 (16:49 +0000)
committerBoris Dorès <babal@videolan.org>
Sun, 25 Sep 2005 16:49:40 +0000 (16:49 +0000)
  channel mixers was broken (again) in 0.8.1 and 0.8.2; hopefully this
  will fix it for good, by allowing audio filters to request a specific
  format rather than imposing them an arbitrary one
- various other small fixes in the audio output core
- option to force detection of Dolby Surround
- simple module to decode Dolby Surround
- increase spatialization with two center speakers and fix channel
  order for 7.1 streams in the headphone channel mixer

15 files changed:
configure.ac
modules/LIST
modules/audio_filter/channel_mixer/Modules.am
modules/audio_filter/channel_mixer/dolby.c [new file with mode: 0644]
modules/audio_filter/channel_mixer/headphone.c
modules/audio_filter/equalizer.c
modules/audio_filter/normvol.c
modules/gui/macosx/extended.m
modules/gui/wxwidgets/extrapanel.cpp
src/audio_output/filters.c
src/audio_output/input.c
src/audio_output/output.c
src/input/decoder.c
src/libvlc.h
vlc.spec.mdk

index 1502e7d..5680ef4 100644 (file)
@@ -1015,7 +1015,7 @@ dnl  VLC_ADD_PLUGINS([externrun])
   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
 
index 9cf0407..17c597b 100644 (file)
@@ -109,6 +109,8 @@ $Id$
 
  * 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
index 7278b05..11f45dd 100644 (file)
@@ -1,3 +1,4 @@
 SOURCES_trivial_channel_mixer = trivial.c
 SOURCES_simple_channel_mixer = simple.c
 SOURCES_headphone_channel_mixer = headphone.c
+SOURCES_dolby_surround_decoder = dolby.c
diff --git a/modules/audio_filter/channel_mixer/dolby.c b/modules/audio_filter/channel_mixer/dolby.c
new file mode 100644 (file)
index 0000000..797f53d
--- /dev/null
@@ -0,0 +1,242 @@
+/*****************************************************************************
+ * 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;
+            }
+        }
+    }
+}
index d6b07af..7949b41 100644 (file)
@@ -2,7 +2,7 @@
  * 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>
@@ -47,11 +47,11 @@ static void DoWork    ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
  *****************************************************************************/
 #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_( \
@@ -184,6 +184,10 @@ static int Init ( aout_filter_t * p_filter , struct aout_filter_sys_t * p_data
 
     /* 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 )
@@ -212,59 +216,64 @@ static int Init ( aout_filter_t * p_filter , struct aout_filter_sys_t * p_data
         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++;
     }
@@ -301,23 +310,54 @@ static int Init ( aout_filter_t * p_filter , struct aout_filter_sys_t * p_data
 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;
@@ -329,13 +369,13 @@ static int Create( vlc_object_t *p_this )
                 , 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;
 }
 
 /*****************************************************************************
index 0bfc27c..9d03e7d 100644 (file)
@@ -136,16 +136,26 @@ static int Open( vlc_object_t *p_this )
 {
     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;
     }
 
index 9dd60b2..98ddfe3 100644 (file)
@@ -98,6 +98,7 @@ vlc_module_end();
 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 ) );
@@ -105,13 +106,22 @@ static int Open( vlc_object_t *p_this )
     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;
     }
 
index d25d216..f502328 100644 (file)
@@ -366,9 +366,9 @@ static VLCExtended *_o_sharedInstance = nil;
     /* 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 ];
     }
 }
 
index 6dba73b..84fb202 100644 (file)
@@ -819,7 +819,7 @@ void ExtraPanel::OnHeadphone( wxCommandEvent &event )
 {
     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 );
index 84be940..4948f6d 100644 (file)
@@ -116,36 +116,49 @@ static int SplitConversion( const audio_sample_format_t * p_input_format,
     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;
     }
 
@@ -177,6 +190,12 @@ int aout_FiltersCreatePipeline( aout_instance_t * p_aout,
 
     /* 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 )
@@ -186,10 +205,16 @@ int aout_FiltersCreatePipeline( aout_instance_t * p_aout,
                                            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 );
@@ -198,31 +223,28 @@ int aout_FiltersCreatePipeline( aout_instance_t * p_aout,
 
         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;
 }
 
index 6c25a21..a1e179f 100644 (file)
 #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 )
@@ -198,13 +169,14 @@ int aout_InputNew( aout_instance_t * p_aout, aout_input_t * p_input )
         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 )
             {
@@ -225,8 +197,6 @@ int aout_InputNew( aout_instance_t * p_aout, aout_input_t * p_input )
                 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 )
@@ -238,33 +208,80 @@ int aout_InputNew( aout_instance_t * p_aout, aout_input_t * p_input )
             }
 
             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;
@@ -273,60 +290,62 @@ int aout_InputNew( aout_instance_t * p_aout, aout_input_t * p_input )
     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(
@@ -334,9 +353,8 @@ int aout_InputNew( aout_instance_t * p_aout, aout_input_t * p_input )
                                     (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;
 
@@ -354,8 +372,10 @@ int aout_InputDelete( aout_instance_t * p_aout, aout_input_t * p_input )
 
     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;
@@ -572,13 +592,38 @@ int aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
     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("");
 
@@ -613,7 +658,7 @@ static int ChangeFiltersString( aout_instance_t * p_aout,
         }
     }
 
-    var_Set( p_aout, "audio-filter", val );
+    var_Set( p_aout, psz_variable, val );
     free( val.psz_string );
     return 1;
 }
@@ -628,23 +673,23 @@ static int VisualizationCallback( vlc_object_t *p_this, char const *psz_cmd,
 
     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
         {
@@ -652,9 +697,9 @@ static int VisualizationCallback( vlc_object_t *p_this, char const *psz_cmd,
             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);
         }
     }
 
@@ -678,14 +723,16 @@ static int EqualizerCallback( vlc_object_t *p_this, char const *psz_cmd,
 
     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 );
 
     }
 
@@ -700,48 +747,3 @@ static int EqualizerCallback( vlc_object_t *p_this, char const *psz_cmd,
 
     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;
-}
index c5106b3..5cee853 100644 (file)
@@ -189,6 +189,7 @@ int aout_OutputNew( aout_instance_t * p_aout,
     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,
index 7589356..158515a 100644 (file)
@@ -853,10 +853,30 @@ static aout_buffer_t *aout_new_buffer( decoder_t *p_dec, int i_samples )
 
     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" );
index 8bbfb85..c873f6d 100644 (file)
@@ -159,6 +159,14 @@ static char *ppsz_snap_formats[] =
     "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 " \
@@ -169,12 +177,6 @@ static char *ppsz_snap_formats[] =
     "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, " \
@@ -960,6 +962,9 @@ vlc_module_begin();
               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 );
@@ -1239,8 +1244,6 @@ vlc_module_begin();
     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 );
index 61a4672..3ce9868 100644 (file)
@@ -808,6 +808,7 @@ rm -fr %buildroot
 
 %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