input.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:26k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * input.c : internal management of input streams for the audio output
  3.  *****************************************************************************
  4.  * Copyright (C) 2002-2004 VideoLAN
  5.  * $Id: input.c 9318 2004-11-14 17:27:44Z gbazin $
  6.  *
  7.  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #include <stdlib.h>                            /* calloc(), malloc(), free() */
  27. #include <string.h>
  28. #include <vlc/vlc.h>
  29. #include <vlc/input.h>                 /* for input_thread_t and i_pts_delay */
  30. #ifdef HAVE_ALLOCA_H
  31. #   include <alloca.h>
  32. #endif
  33. #include "audio_output.h"
  34. #include "aout_internal.h"
  35. static int VisualizationCallback( vlc_object_t *, char const *,
  36.                                   vlc_value_t, vlc_value_t, void * );
  37. static int EqualizerCallback( vlc_object_t *, char const *,
  38.                               vlc_value_t, vlc_value_t, void * );
  39. static aout_filter_t * allocateUserChannelMixer( aout_instance_t *,
  40.                                                  audio_sample_format_t *,
  41.                                                  audio_sample_format_t * );
  42. /*****************************************************************************
  43.  * aout_InputNew : allocate a new input and rework the filter pipeline
  44.  *****************************************************************************/
  45. int aout_InputNew( aout_instance_t * p_aout, aout_input_t * p_input )
  46. {
  47.     audio_sample_format_t user_filter_format;
  48.     audio_sample_format_t intermediate_format;/* input of resampler */
  49.     vlc_value_t val, text;
  50.     char * psz_filters;
  51.     aout_filter_t * p_user_channel_mixer;
  52.     aout_FormatPrint( p_aout, "input", &p_input->input );
  53.     /* Prepare FIFO. */
  54.     aout_FifoInit( p_aout, &p_input->fifo, p_aout->mixer.mixer.i_rate );
  55.     p_input->p_first_byte_to_mix = NULL;
  56.     /* Prepare format structure */
  57.     memcpy( &intermediate_format, &p_aout->mixer.mixer,
  58.             sizeof(audio_sample_format_t) );
  59.     intermediate_format.i_rate = p_input->input.i_rate;
  60.     /* Try to use the channel mixer chosen by the user */
  61.     memcpy ( &user_filter_format, &intermediate_format,
  62.              sizeof(audio_sample_format_t) );
  63.     user_filter_format.i_physical_channels = p_input->input.i_physical_channels;
  64.     user_filter_format.i_original_channels = p_input->input.i_original_channels;
  65.     user_filter_format.i_bytes_per_frame = user_filter_format.i_bytes_per_frame
  66.                               * aout_FormatNbChannels( &user_filter_format )
  67.                               / aout_FormatNbChannels( &intermediate_format );
  68.     p_user_channel_mixer = allocateUserChannelMixer( p_aout, &user_filter_format,
  69.                                                    &intermediate_format );
  70.     /* If it failed, let the main pipeline do channel mixing */
  71.     if ( ! p_user_channel_mixer )
  72.     {
  73.         memcpy ( &user_filter_format, &intermediate_format,
  74.                  sizeof(audio_sample_format_t) );
  75.     }
  76.     /* Create filters. */
  77.     if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters,
  78.                                      &p_input->i_nb_filters,
  79.                                      &p_input->input,
  80.                                      &user_filter_format
  81.                                      ) < 0 )
  82.     {
  83.         msg_Err( p_aout, "couldn't set an input pipeline" );
  84.         aout_FifoDestroy( p_aout, &p_input->fifo );
  85.         p_input->b_error = 1;
  86.         return -1;
  87.     }
  88.     /* Now add user filters */
  89.     if( var_Type( p_aout, "visual" ) == 0 )
  90.     {
  91.         module_t *p_module;
  92.         var_Create( p_aout, "visual", VLC_VAR_STRING | VLC_VAR_HASCHOICE );
  93.         text.psz_string = _("Visualizations");
  94.         var_Change( p_aout, "visual", VLC_VAR_SETTEXT, &text, NULL );
  95.         val.psz_string = ""; text.psz_string = _("Disable");
  96.         var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
  97.         val.psz_string = "random"; text.psz_string = _("Random");
  98.         var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
  99.         val.psz_string = "scope"; text.psz_string = _("Scope");
  100.         var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
  101.         val.psz_string = "spectrum"; text.psz_string = _("Spectrum");
  102.         var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
  103.         /* Look for goom plugin */
  104.         p_module = config_FindModule( VLC_OBJECT(p_aout), "goom" );
  105.         if( p_module )
  106.         {
  107.             val.psz_string = "goom"; text.psz_string = "Goom";
  108.             var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
  109.         }
  110.         /* Look for galaktos plugin */
  111.         p_module = config_FindModule( VLC_OBJECT(p_aout), "galaktos" );
  112.         if( p_module )
  113.         {
  114.             val.psz_string = "galaktos"; text.psz_string = "GaLaktos";
  115.             var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
  116.         }
  117.         if( var_Get( p_aout, "effect-list", &val ) == VLC_SUCCESS )
  118.         {
  119.             var_Set( p_aout, "visual", val );
  120.             if( val.psz_string ) free( val.psz_string );
  121.         }
  122.         var_AddCallback( p_aout, "visual", VisualizationCallback, NULL );
  123.     }
  124.     if( var_Type( p_aout, "equalizer" ) == 0 )
  125.     {
  126.         module_config_t *p_config;
  127. int i;
  128. p_config = config_FindConfig( VLC_OBJECT(p_aout), "equalizer-preset" );
  129. if( p_config && p_config->i_list )
  130. {
  131.       var_Create( p_aout, "equalizer",
  132. VLC_VAR_STRING | VLC_VAR_HASCHOICE );
  133.     text.psz_string = _("Equalizer");
  134.     var_Change( p_aout, "equalizer", VLC_VAR_SETTEXT, &text, NULL );
  135.     val.psz_string = ""; text.psz_string = _("Disable");
  136.     var_Change( p_aout, "equalizer", VLC_VAR_ADDCHOICE, &val, &text );
  137.     for( i = 0; i < p_config->i_list; i++ )
  138.     {
  139. val.psz_string = p_config->ppsz_list[i];
  140. text.psz_string = p_config->ppsz_list_text[i];
  141. var_Change( p_aout, "equalizer", VLC_VAR_ADDCHOICE,
  142.     &val, &text );
  143.     }
  144.     var_AddCallback( p_aout, "equalizer", EqualizerCallback, NULL );
  145. }
  146.     }
  147.     if( var_Type( p_aout, "audio-filter" ) == 0 )
  148.     {
  149.         var_Create( p_aout, "audio-filter",
  150.                     VLC_VAR_STRING | VLC_VAR_DOINHERIT );
  151.         text.psz_string = _("Audio filters");
  152.         var_Change( p_aout, "audio-filter", VLC_VAR_SETTEXT, &text, NULL );
  153.     }
  154.     var_Get( p_aout, "audio-filter", &val );
  155.     psz_filters = val.psz_string;
  156.     if( psz_filters && *psz_filters )
  157.     {
  158.         char *psz_parser = psz_filters;
  159.         char *psz_next;
  160.         while( psz_parser && *psz_parser )
  161.         {
  162.             aout_filter_t * p_filter;
  163.             if( p_input->i_nb_filters >= AOUT_MAX_FILTERS )
  164.             {
  165.                 msg_Dbg( p_aout, "max filter reached (%d)", AOUT_MAX_FILTERS );
  166.                 break;
  167.             }
  168.             while( *psz_parser == ' ' && *psz_parser == ',' )
  169.             {
  170.                 psz_parser++;
  171.             }
  172.             if( ( psz_next = strchr( psz_parser , ','  ) ) )
  173.             {
  174.                 *psz_next++ = '';
  175.             }
  176.             if( *psz_parser =='' )
  177.             {
  178.                 break;
  179.             }
  180.             msg_Dbg( p_aout, "user filter "%s"", psz_parser );
  181.             /* Create a VLC object */
  182.             p_filter = vlc_object_create( p_aout, sizeof(aout_filter_t) );
  183.             if( p_filter == NULL )
  184.             {
  185.                 msg_Err( p_aout, "cannot add user filter %s (skipped)",
  186.                          psz_parser );
  187.                 psz_parser = psz_next;
  188.                 continue;
  189.             }
  190.             vlc_object_attach( p_filter , p_aout );
  191.             memcpy( &p_filter->input, &user_filter_format,
  192.                     sizeof(audio_sample_format_t) );
  193.             memcpy( &p_filter->output, &user_filter_format,
  194.                     sizeof(audio_sample_format_t) );
  195.             p_filter->p_module =
  196.                 module_Need( p_filter,"audio filter", psz_parser, VLC_TRUE );
  197.             if( p_filter->p_module== NULL )
  198.             {
  199.                 msg_Err( p_aout, "cannot add user filter %s (skipped)",
  200.                          psz_parser );
  201.                 vlc_object_detach( p_filter );
  202.                 vlc_object_destroy( p_filter );
  203.                 psz_parser = psz_next;
  204.                 continue;
  205.             }
  206.             p_filter->b_continuity = VLC_FALSE;
  207.             p_input->pp_filters[p_input->i_nb_filters++] = p_filter;
  208.             /* next filter if any */
  209.             psz_parser = psz_next;
  210.         }
  211.     }
  212.     if( psz_filters ) free( psz_filters );
  213.     /* Attach the user channel mixer */
  214.     if ( p_user_channel_mixer )
  215.     {
  216.         p_input->pp_filters[p_input->i_nb_filters++] = p_user_channel_mixer;
  217.     }
  218.     /* Prepare hints for the buffer allocator. */
  219.     p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
  220.     p_input->input_alloc.i_bytes_per_sec = -1;
  221.     if ( AOUT_FMT_NON_LINEAR( &p_aout->mixer.mixer ) )
  222.     {
  223.         p_input->i_nb_resamplers = 0;
  224.     }
  225.     else
  226.     {
  227.         /* Create resamplers. */
  228.         intermediate_format.i_rate = (__MAX(p_input->input.i_rate,
  229.                                             p_aout->mixer.mixer.i_rate)
  230.                                  * (100 + AOUT_MAX_RESAMPLING)) / 100;
  231.         if ( intermediate_format.i_rate == p_aout->mixer.mixer.i_rate )
  232.         {
  233.             /* Just in case... */
  234.             intermediate_format.i_rate++;
  235.         }
  236.         if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_resamplers,
  237.                                          &p_input->i_nb_resamplers,
  238.                                          &intermediate_format,
  239.                                          &p_aout->mixer.mixer ) < 0 )
  240.         {
  241.             msg_Err( p_aout, "couldn't set a resampler pipeline" );
  242.             aout_FiltersDestroyPipeline( p_aout, p_input->pp_filters,
  243.                                          p_input->i_nb_filters );
  244.             aout_FifoDestroy( p_aout, &p_input->fifo );
  245.             var_Destroy( p_aout, "visual" );
  246.             p_input->b_error = 1;
  247.             return -1;
  248.         }
  249.         aout_FiltersHintBuffers( p_aout, p_input->pp_resamplers,
  250.                                  p_input->i_nb_resamplers,
  251.                                  &p_input->input_alloc );
  252.         /* Setup the initial rate of the resampler */
  253.         p_input->pp_resamplers[0]->input.i_rate = p_input->input.i_rate;
  254.     }
  255.     p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
  256.     p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
  257.     aout_FiltersHintBuffers( p_aout, p_input->pp_filters,
  258.                              p_input->i_nb_filters,
  259.                              &p_input->input_alloc );
  260.     /* i_bytes_per_sec is still == -1 if no filters */
  261.     p_input->input_alloc.i_bytes_per_sec = __MAX(
  262.                                     p_input->input_alloc.i_bytes_per_sec,
  263.                                     (int)(p_input->input.i_bytes_per_frame
  264.                                      * p_input->input.i_rate
  265.                                      / p_input->input.i_frame_length) );
  266.     /* Allocate in the heap, it is more convenient for the decoder. */
  267.     p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
  268.     p_input->b_error = VLC_FALSE;
  269.     p_input->b_restart = VLC_FALSE;
  270.     return 0;
  271. }
  272. /*****************************************************************************
  273.  * aout_InputDelete : delete an input
  274.  *****************************************************************************
  275.  * This function must be entered with the mixer lock.
  276.  *****************************************************************************/
  277. int aout_InputDelete( aout_instance_t * p_aout, aout_input_t * p_input )
  278. {
  279.     if ( p_input->b_error ) return 0;
  280.     aout_FiltersDestroyPipeline( p_aout, p_input->pp_filters,
  281.                                  p_input->i_nb_filters );
  282.     aout_FiltersDestroyPipeline( p_aout, p_input->pp_resamplers,
  283.                                  p_input->i_nb_resamplers );
  284.     aout_FifoDestroy( p_aout, &p_input->fifo );
  285.     return 0;
  286. }
  287. /*****************************************************************************
  288.  * aout_InputPlay : play a buffer
  289.  *****************************************************************************
  290.  * This function must be entered with the input lock.
  291.  *****************************************************************************/
  292. int aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
  293.                     aout_buffer_t * p_buffer )
  294. {
  295.     mtime_t start_date;
  296.     if( p_input->b_restart )
  297.     {
  298.         aout_fifo_t fifo, dummy_fifo;
  299.         byte_t      *p_first_byte_to_mix;
  300.         vlc_mutex_lock( &p_aout->mixer_lock );
  301.         /* A little trick to avoid loosing our input fifo */
  302.         aout_FifoInit( p_aout, &dummy_fifo, p_aout->mixer.mixer.i_rate );
  303.         p_first_byte_to_mix = p_input->p_first_byte_to_mix;
  304.         fifo = p_input->fifo;
  305.         p_input->fifo = dummy_fifo;
  306.         aout_InputDelete( p_aout, p_input );
  307.         aout_InputNew( p_aout, p_input );
  308.         p_input->p_first_byte_to_mix = p_first_byte_to_mix;
  309.         p_input->fifo = fifo;
  310.         vlc_mutex_unlock( &p_aout->mixer_lock );
  311.     }
  312.     /* We don't care if someone changes the start date behind our back after
  313.      * this. We'll deal with that when pushing the buffer, and compensate
  314.      * with the next incoming buffer. */
  315.     vlc_mutex_lock( &p_aout->input_fifos_lock );
  316.     start_date = aout_FifoNextStart( p_aout, &p_input->fifo );
  317.     vlc_mutex_unlock( &p_aout->input_fifos_lock );
  318.     if ( start_date != 0 && start_date < mdate() )
  319.     {
  320.         /* The decoder is _very_ late. This can only happen if the user
  321.          * pauses the stream (or if the decoder is buggy, which cannot
  322.          * happen :). */
  323.         msg_Warn( p_aout, "computed PTS is out of range ("I64Fd"), "
  324.                   "clearing out", mdate() - start_date );
  325.         vlc_mutex_lock( &p_aout->input_fifos_lock );
  326.         aout_FifoSet( p_aout, &p_input->fifo, 0 );
  327.         p_input->p_first_byte_to_mix = NULL;
  328.         vlc_mutex_unlock( &p_aout->input_fifos_lock );
  329.         if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
  330.             msg_Warn( p_aout, "timing screwed, stopping resampling" );
  331.         p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
  332.         if ( p_input->i_nb_resamplers != 0 )
  333.         {
  334.             p_input->pp_resamplers[0]->input.i_rate = p_input->input.i_rate;
  335.             p_input->pp_resamplers[0]->b_continuity = VLC_FALSE;
  336.         }
  337.         start_date = 0;
  338.     }
  339.     if ( p_buffer->start_date < mdate() + AOUT_MIN_PREPARE_TIME )
  340.     {
  341.         /* The decoder gives us f*cked up PTS. It's its business, but we
  342.          * can't present it anyway, so drop the buffer. */
  343.         msg_Warn( p_aout, "PTS is out of range ("I64Fd"), dropping buffer",
  344.                   mdate() - p_buffer->start_date );
  345.         aout_BufferFree( p_buffer );
  346.         p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
  347.         if ( p_input->i_nb_resamplers != 0 )
  348.         {
  349.             p_input->pp_resamplers[0]->input.i_rate = p_input->input.i_rate;
  350.             p_input->pp_resamplers[0]->b_continuity = VLC_FALSE;
  351.         }
  352.         return 0;
  353.     }
  354.     /* If the audio drift is too big then it's not worth trying to resample
  355.      * the audio. */
  356.     if ( start_date != 0 &&
  357.          ( start_date < p_buffer->start_date - 3 * AOUT_PTS_TOLERANCE ) )
  358.     {
  359.         msg_Warn( p_aout, "audio drift is too big ("I64Fd"), clearing out",
  360.                   start_date - p_buffer->start_date );
  361.         vlc_mutex_lock( &p_aout->input_fifos_lock );
  362.         aout_FifoSet( p_aout, &p_input->fifo, 0 );
  363.         p_input->p_first_byte_to_mix = NULL;
  364.         vlc_mutex_unlock( &p_aout->input_fifos_lock );
  365.         if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
  366.             msg_Warn( p_aout, "timing screwed, stopping resampling" );
  367.         p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
  368.         if ( p_input->i_nb_resamplers != 0 )
  369.         {
  370.             p_input->pp_resamplers[0]->input.i_rate = p_input->input.i_rate;
  371.             p_input->pp_resamplers[0]->b_continuity = VLC_FALSE;
  372.         }
  373.         start_date = 0;
  374.     }
  375.     else if ( start_date != 0 &&
  376.               ( start_date > p_buffer->start_date + 3 * AOUT_PTS_TOLERANCE ) )
  377.     {
  378.         msg_Warn( p_aout, "audio drift is too big ("I64Fd"), dropping buffer",
  379.                   start_date - p_buffer->start_date );
  380.         aout_BufferFree( p_buffer );
  381.         return 0;
  382.     }
  383.     if ( start_date == 0 ) start_date = p_buffer->start_date;
  384.     /* Run pre-filters. */
  385.     aout_FiltersPlay( p_aout, p_input->pp_filters, p_input->i_nb_filters,
  386.                       &p_buffer );
  387.     /* Run the resampler if needed.
  388.      * We first need to calculate the output rate of this resampler. */
  389.     if ( ( p_input->i_resampling_type == AOUT_RESAMPLING_NONE ) &&
  390.          ( start_date < p_buffer->start_date - AOUT_PTS_TOLERANCE
  391.            || start_date > p_buffer->start_date + AOUT_PTS_TOLERANCE ) &&
  392.          p_input->i_nb_resamplers > 0 )
  393.     {
  394.         /* Can happen in several circumstances :
  395.          * 1. A problem at the input (clock drift)
  396.          * 2. A small pause triggered by the user
  397.          * 3. Some delay in the output stage, causing a loss of lip
  398.          *    synchronization
  399.          * Solution : resample the buffer to avoid a scratch.
  400.          */
  401.         mtime_t drift = p_buffer->start_date - start_date;
  402.         p_input->i_resamp_start_date = mdate();
  403.         p_input->i_resamp_start_drift = (int)drift;
  404.         if ( drift > 0 )
  405.             p_input->i_resampling_type = AOUT_RESAMPLING_DOWN;
  406.         else
  407.             p_input->i_resampling_type = AOUT_RESAMPLING_UP;
  408.         msg_Warn( p_aout, "buffer is "I64Fd" %s, triggering %ssampling",
  409.                           drift > 0 ? drift : -drift,
  410.                           drift > 0 ? "in advance" : "late",
  411.                           drift > 0 ? "down" : "up");
  412.     }
  413.     if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
  414.     {
  415.         /* Resampling has been triggered previously (because of dates
  416.          * mismatch). We want the resampling to happen progressively so
  417.          * it isn't too audible to the listener. */
  418.         if( p_input->i_resampling_type == AOUT_RESAMPLING_UP )
  419.         {
  420.             p_input->pp_resamplers[0]->input.i_rate += 2; /* Hz */
  421.         }
  422.         else
  423.         {
  424.             p_input->pp_resamplers[0]->input.i_rate -= 2; /* Hz */
  425.         }
  426.         /* Check if everything is back to normal, in which case we can stop the
  427.          * resampling */
  428.         if( p_input->pp_resamplers[0]->input.i_rate ==
  429.               p_input->input.i_rate )
  430.         {
  431.             p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
  432.             msg_Warn( p_aout, "resampling stopped after "I64Fi" usec "
  433.                       "(drift: "I64Fi")",
  434.                       mdate() - p_input->i_resamp_start_date,
  435.                       p_buffer->start_date - start_date);
  436.         }
  437.         else if( abs( (int)(p_buffer->start_date - start_date) ) <
  438.                  abs( p_input->i_resamp_start_drift ) / 2 )
  439.         {
  440.             /* if we reduced the drift from half, then it is time to switch
  441.              * back the resampling direction. */
  442.             if( p_input->i_resampling_type == AOUT_RESAMPLING_UP )
  443.                 p_input->i_resampling_type = AOUT_RESAMPLING_DOWN;
  444.             else
  445.                 p_input->i_resampling_type = AOUT_RESAMPLING_UP;
  446.             p_input->i_resamp_start_drift = 0;
  447.         }
  448.         else if( p_input->i_resamp_start_drift &&
  449.                  ( abs( (int)(p_buffer->start_date - start_date) ) >
  450.                    abs( p_input->i_resamp_start_drift ) * 3 / 2 ) )
  451.         {
  452.             /* If the drift is increasing and not decreasing, than something
  453.              * is bad. We'd better stop the resampling right now. */
  454.             msg_Warn( p_aout, "timing screwed, stopping resampling" );
  455.             p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
  456.             p_input->pp_resamplers[0]->input.i_rate = p_input->input.i_rate;
  457.         }
  458.     }
  459.     /* Adding the start date will be managed by aout_FifoPush(). */
  460.     p_buffer->end_date = start_date +
  461.         (p_buffer->end_date - p_buffer->start_date);
  462.     p_buffer->start_date = start_date;
  463.     /* Actually run the resampler now. */
  464.     if ( p_input->i_nb_resamplers > 0 )
  465.     {
  466.         aout_FiltersPlay( p_aout, p_input->pp_resamplers,
  467.                           p_input->i_nb_resamplers,
  468.                           &p_buffer );
  469.     }
  470.     vlc_mutex_lock( &p_aout->input_fifos_lock );
  471.     aout_FifoPush( p_aout, &p_input->fifo, p_buffer );
  472.     vlc_mutex_unlock( &p_aout->input_fifos_lock );
  473.     return 0;
  474. }
  475. static int ChangeFiltersString( aout_instance_t * p_aout,
  476.                                  char *psz_name, vlc_bool_t b_add )
  477. {
  478.     vlc_value_t val;
  479.     char *psz_parser;
  480.     var_Get( p_aout, "audio-filter", &val );
  481.     if( !val.psz_string ) val.psz_string = strdup("");
  482.     psz_parser = strstr( val.psz_string, psz_name );
  483.     if( b_add )
  484.     {
  485.         if( !psz_parser )
  486.         {
  487.             psz_parser = val.psz_string;
  488.             asprintf( &val.psz_string, (*val.psz_string) ? "%s,%s" : "%s%s",
  489.                       val.psz_string, psz_name );
  490.             free( psz_parser );
  491.         }
  492.         else
  493.         {
  494.             return 0;
  495.         }
  496.     }
  497.     else
  498.     {
  499.         if( psz_parser )
  500.         {
  501.             memmove( psz_parser, psz_parser + strlen(psz_name) +
  502.                      (*(psz_parser + strlen(psz_name)) == ',' ? 1 : 0 ),
  503.                      strlen(psz_parser + strlen(psz_name)) + 1 );
  504.         }
  505.         else
  506.         {
  507.             free( val.psz_string );
  508.             return 0;
  509.         }
  510.     }
  511.     var_Set( p_aout, "audio-filter", val );
  512.     free( val.psz_string );
  513.     return 1;
  514. }
  515. static int VisualizationCallback( vlc_object_t *p_this, char const *psz_cmd,
  516.                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
  517. {
  518.     aout_instance_t *p_aout = (aout_instance_t *)p_this;
  519.     char *psz_mode = newval.psz_string;
  520.     vlc_value_t val;
  521.     int i;
  522.     if( !psz_mode || !*psz_mode )
  523.     {
  524.         ChangeFiltersString( p_aout, "goom", VLC_FALSE );
  525.         ChangeFiltersString( p_aout, "visual", VLC_FALSE );
  526.         ChangeFiltersString( p_aout, "galaktos", VLC_FALSE );
  527.     }
  528.     else
  529.     {
  530.         if( !strcmp( "goom", psz_mode ) )
  531.         {
  532.             ChangeFiltersString( p_aout, "visual", VLC_FALSE );
  533.             ChangeFiltersString( p_aout, "goom", VLC_TRUE );
  534.             ChangeFiltersString( p_aout, "galaktos", VLC_FALSE );
  535.         }
  536.         else if( !strcmp( "galaktos", psz_mode ) )
  537.         {
  538.             ChangeFiltersString( p_aout, "visual", VLC_FALSE );
  539.             ChangeFiltersString( p_aout, "goom", VLC_FALSE );
  540.             ChangeFiltersString( p_aout, "galaktos", VLC_TRUE );
  541.         }
  542.         else
  543.         {
  544.             val.psz_string = psz_mode;
  545.             var_Create( p_aout, "effect-list", VLC_VAR_STRING );
  546.             var_Set( p_aout, "effect-list", val );
  547.             ChangeFiltersString( p_aout, "goom", VLC_FALSE );
  548.             ChangeFiltersString( p_aout, "visual", VLC_TRUE );
  549.             ChangeFiltersString( p_aout, "galaktos", VLC_FALSE );
  550.         }
  551.     }
  552.     /* That sucks */
  553.     for( i = 0; i < p_aout->i_nb_inputs; i++ )
  554.     {
  555.         p_aout->pp_inputs[i]->b_restart = VLC_TRUE;
  556.     }
  557.     return VLC_SUCCESS;
  558. }
  559. static int EqualizerCallback( vlc_object_t *p_this, char const *psz_cmd,
  560.                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
  561. {
  562.     aout_instance_t *p_aout = (aout_instance_t *)p_this;
  563.     char *psz_mode = newval.psz_string;
  564.     vlc_value_t val;
  565.     int i;
  566.     int i_ret;
  567.     if( !psz_mode || !*psz_mode )
  568.     {
  569.         i_ret = ChangeFiltersString( p_aout, "equalizer", VLC_FALSE );
  570.     }
  571.     else
  572.     {
  573.         val.psz_string = psz_mode;
  574.         var_Create( p_aout, "equalizer-preset", VLC_VAR_STRING );
  575.         var_Set( p_aout, "equalizer-preset", val );
  576.         i_ret = ChangeFiltersString( p_aout, "equalizer", VLC_TRUE );
  577.     }
  578.     /* That sucks */
  579.     if( i_ret == 1 )
  580.     {
  581.         for( i = 0; i < p_aout->i_nb_inputs; i++ )
  582.         {
  583.             p_aout->pp_inputs[i]->b_restart = VLC_TRUE;
  584.         }
  585.     }
  586.     return VLC_SUCCESS;
  587. }
  588. static aout_filter_t * allocateUserChannelMixer( aout_instance_t * p_aout,
  589.                                      audio_sample_format_t * p_input_format,
  590.                                      audio_sample_format_t * p_output_format )
  591. {
  592.     aout_filter_t * p_channel_mixer;
  593.     /* Retreive user preferred channel mixer */
  594.     char * psz_name = config_GetPsz( p_aout, "audio-channel-mixer" );
  595.     /* Not specified => let the main pipeline do the mixing */
  596.     if ( ! psz_name ) return NULL;
  597.     /* Debug information */
  598.     aout_FormatsPrint( p_aout, "channel mixer", p_input_format,
  599.                        p_output_format );
  600.     /* Create a VLC object */
  601.     p_channel_mixer = vlc_object_create( p_aout, sizeof(aout_filter_t) );
  602.     if( p_channel_mixer == NULL )
  603.     {
  604.         msg_Err( p_aout, "cannot add user channel mixer %s", psz_name );
  605.         return NULL;
  606.     }
  607.     vlc_object_attach( p_channel_mixer , p_aout );
  608.     /* Attach the suitable module */
  609.     memcpy( &p_channel_mixer->input, p_input_format,
  610.                     sizeof(audio_sample_format_t) );
  611.     memcpy( &p_channel_mixer->output, p_output_format,
  612.                     sizeof(audio_sample_format_t) );
  613.     p_channel_mixer->p_module =
  614.         module_Need( p_channel_mixer,"audio filter", psz_name, VLC_TRUE );
  615.     if( p_channel_mixer->p_module== NULL )
  616.     {
  617.         msg_Err( p_aout, "cannot add user channel mixer %s", psz_name );
  618.         vlc_object_detach( p_channel_mixer );
  619.         vlc_object_destroy( p_channel_mixer );
  620.         return NULL;
  621.     }
  622.     p_channel_mixer->b_continuity = VLC_FALSE;
  623.     /* Ok */
  624.     return p_channel_mixer;
  625. }