input.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:37k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * input.c : internal management of input streams for the audio output
  3.  *****************************************************************************
  4.  * Copyright (C) 2002-2007 the VideoLAN team
  5.  * $Id: b4d9c485469fcf366a60ee8ba5b37ab4f1d3dc65 $
  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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #ifdef HAVE_CONFIG_H
  27. # include "config.h"
  28. #endif
  29. #include <vlc_common.h>
  30. #include <stdio.h>
  31. #include <string.h>
  32. #include <math.h>
  33. #include <assert.h>
  34. #include <vlc_input.h>
  35. #include <vlc_vout.h>                  /* for vout_Request */
  36. #ifdef HAVE_ALLOCA_H
  37. #   include <alloca.h>
  38. #endif
  39. #include <vlc_aout.h>
  40. #include <libvlc.h>
  41. #include "aout_internal.h"
  42. #define AOUT_ASSERT_MIXER_LOCKED vlc_assert_locked( &p_aout->mixer_lock )
  43. #define AOUT_ASSERT_INPUT_LOCKED vlc_assert_locked( &p_input->lock )
  44. static void inputFailure( aout_instance_t *, aout_input_t *, const char * );
  45. static void inputDrop( aout_input_t *, aout_buffer_t * );
  46. static void inputResamplingStop( aout_input_t *p_input );
  47. static int VisualizationCallback( vlc_object_t *, char const *,
  48.                                   vlc_value_t, vlc_value_t, void * );
  49. static int EqualizerCallback( vlc_object_t *, char const *,
  50.                               vlc_value_t, vlc_value_t, void * );
  51. static int ReplayGainCallback( vlc_object_t *, char const *,
  52.                                vlc_value_t, vlc_value_t, void * );
  53. static void ReplayGainSelect( aout_instance_t *, aout_input_t * );
  54. static vout_thread_t *RequestVout( void *,
  55.                                    vout_thread_t *, video_format_t *, bool );
  56. static vout_thread_t *RequestVoutFromFilter( void *,
  57.                                              vout_thread_t *, video_format_t *, bool  );
  58. /*****************************************************************************
  59.  * aout_InputNew : allocate a new input and rework the filter pipeline
  60.  *****************************************************************************/
  61. int aout_InputNew( aout_instance_t * p_aout, aout_input_t * p_input, const aout_request_vout_t *p_request_vout )
  62. {
  63.     audio_sample_format_t chain_input_format;
  64.     audio_sample_format_t chain_output_format;
  65.     vlc_value_t val, text;
  66.     char *psz_filters, *psz_visual, *psz_scaletempo;
  67.     int i_visual;
  68.     aout_FormatPrint( p_aout, "input", &p_input->input );
  69.     p_input->i_nb_resamplers = p_input->i_nb_filters = 0;
  70.     /* Prepare FIFO. */
  71.     aout_FifoInit( p_aout, &p_input->fifo, p_aout->mixer.mixer.i_rate );
  72.     p_input->p_first_byte_to_mix = NULL;
  73.     /* */
  74.     if( p_request_vout )
  75.     {
  76.         p_input->request_vout = *p_request_vout;
  77.     }
  78.     else
  79.     {
  80.         p_input->request_vout.pf_request_vout = RequestVout;
  81.         p_input->request_vout.p_private = p_aout;
  82.     }
  83.     /* Prepare format structure */
  84.     memcpy( &chain_input_format, &p_input->input,
  85.             sizeof(audio_sample_format_t) );
  86.     memcpy( &chain_output_format, &p_aout->mixer.mixer,
  87.             sizeof(audio_sample_format_t) );
  88.     chain_output_format.i_rate = p_input->input.i_rate;
  89.     aout_FormatPrepare( &chain_output_format );
  90.     /* Now add user filters */
  91.     if( var_Type( p_aout, "visual" ) == 0 )
  92.     {
  93.         var_Create( p_aout, "visual", VLC_VAR_STRING | VLC_VAR_HASCHOICE );
  94.         text.psz_string = _("Visualizations");
  95.         var_Change( p_aout, "visual", VLC_VAR_SETTEXT, &text, NULL );
  96.         val.psz_string = (char*)""; text.psz_string = _("Disable");
  97.         var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
  98.         val.psz_string = (char*)"spectrometer"; text.psz_string = _("Spectrometer");
  99.         var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
  100.         val.psz_string = (char*)"scope"; text.psz_string = _("Scope");
  101.         var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
  102.         val.psz_string = (char*)"spectrum"; text.psz_string = _("Spectrum");
  103.         var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
  104.         val.psz_string = (char*)"vuMeter"; text.psz_string = _("Vu meter");
  105.         var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
  106.         /* Look for goom plugin */
  107.         if( module_exists( "goom" ) )
  108.         {
  109.             val.psz_string = (char*)"goom"; text.psz_string = (char*)"Goom";
  110.             var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
  111.         }
  112.         /* Look for galaktos plugin */
  113.         if( module_exists( "galaktos" ) )
  114.         {
  115.             val.psz_string = (char*)"galaktos"; text.psz_string = (char*)"GaLaktos";
  116.             var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
  117.         }
  118.         if( var_Get( p_aout, "effect-list", &val ) == VLC_SUCCESS )
  119.         {
  120.             var_SetString( p_aout, "visual", val.psz_string );
  121.             free( val.psz_string );
  122.         }
  123.         var_AddCallback( p_aout, "visual", VisualizationCallback, NULL );
  124.     }
  125.     if( var_Type( p_aout, "equalizer" ) == 0 )
  126.     {
  127.         module_config_t *p_config;
  128.         int i;
  129.         p_config = config_FindConfig( VLC_OBJECT(p_aout), "equalizer-preset" );
  130.         if( p_config && p_config->i_list )
  131.         {
  132.                var_Create( p_aout, "equalizer",
  133.                            VLC_VAR_STRING | VLC_VAR_HASCHOICE );
  134.             text.psz_string = _("Equalizer");
  135.             var_Change( p_aout, "equalizer", VLC_VAR_SETTEXT, &text, NULL );
  136.             val.psz_string = (char*)""; text.psz_string = _("Disable");
  137.             var_Change( p_aout, "equalizer", VLC_VAR_ADDCHOICE, &val, &text );
  138.             for( i = 0; i < p_config->i_list; i++ )
  139.             {
  140.                 val.psz_string = (char *)p_config->ppsz_list[i];
  141.                 text.psz_string = (char *)p_config->ppsz_list_text[i];
  142.                 var_Change( p_aout, "equalizer", VLC_VAR_ADDCHOICE,
  143.                             &val, &text );
  144.             }
  145.             var_AddCallback( p_aout, "equalizer", EqualizerCallback, NULL );
  146.         }
  147.     }
  148.     if( var_Type( p_aout, "audio-filter" ) == 0 )
  149.     {
  150.         var_Create( p_aout, "audio-filter",
  151.                     VLC_VAR_STRING | VLC_VAR_DOINHERIT );
  152.         text.psz_string = _("Audio filters");
  153.         var_Change( p_aout, "audio-filter", VLC_VAR_SETTEXT, &text, NULL );
  154.     }
  155.     if( var_Type( p_aout, "audio-visual" ) == 0 )
  156.     {
  157.         var_Create( p_aout, "audio-visual",
  158.                     VLC_VAR_STRING | VLC_VAR_DOINHERIT );
  159.         text.psz_string = _("Audio visualizations");
  160.         var_Change( p_aout, "audio-visual", VLC_VAR_SETTEXT, &text, NULL );
  161.     }
  162.     if( var_Type( p_aout, "audio-replay-gain-mode" ) == 0 )
  163.     {
  164.         module_config_t *p_config;
  165.         int i;
  166.         p_config = config_FindConfig( VLC_OBJECT(p_aout), "audio-replay-gain-mode" );
  167.         if( p_config && p_config->i_list )
  168.         {
  169.             var_Create( p_aout, "audio-replay-gain-mode",
  170.                         VLC_VAR_STRING | VLC_VAR_DOINHERIT );
  171.             text.psz_string = _("Replay gain");
  172.             var_Change( p_aout, "audio-replay-gain-mode", VLC_VAR_SETTEXT, &text, NULL );
  173.             for( i = 0; i < p_config->i_list; i++ )
  174.             {
  175.                 val.psz_string = (char *)p_config->ppsz_list[i];
  176.                 text.psz_string = (char *)p_config->ppsz_list_text[i];
  177.                 var_Change( p_aout, "audio-replay-gain-mode", VLC_VAR_ADDCHOICE,
  178.                             &val, &text );
  179.             }
  180.             var_AddCallback( p_aout, "audio-replay-gain-mode", ReplayGainCallback, NULL );
  181.         }
  182.     }
  183.     if( var_Type( p_aout, "audio-replay-gain-preamp" ) == 0 )
  184.     {
  185.         var_Create( p_aout, "audio-replay-gain-preamp",
  186.                     VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
  187.     }
  188.     if( var_Type( p_aout, "audio-replay-gain-default" ) == 0 )
  189.     {
  190.         var_Create( p_aout, "audio-replay-gain-default",
  191.                     VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
  192.     }
  193.     if( var_Type( p_aout, "audio-replay-gain-peak-protection" ) == 0 )
  194.     {
  195.         var_Create( p_aout, "audio-replay-gain-peak-protection",
  196.                     VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
  197.     }
  198.     if( var_Type( p_aout, "audio-time-stretch" ) == 0 )
  199.     {
  200.         var_Create( p_aout, "audio-time-stretch",
  201.                     VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
  202.     }
  203.     psz_filters = var_GetString( p_aout, "audio-filter" );
  204.     psz_visual = var_GetString( p_aout, "audio-visual");
  205.     psz_scaletempo = var_GetBool( p_aout, "audio-time-stretch" ) ? strdup( "scaletempo" ) : NULL;
  206.     p_input->b_recycle_vout = psz_visual && *psz_visual;
  207.     /* parse user filter lists */
  208.     for( i_visual = 0; i_visual < 3 && !AOUT_FMT_NON_LINEAR(&chain_output_format); i_visual++ )
  209.     {
  210.         char *ppsz_array[] = { psz_scaletempo, psz_filters, psz_visual };
  211.         char *psz_next = NULL;
  212.         char *psz_parser = ppsz_array[i_visual];
  213.         if( psz_parser == NULL || !*psz_parser )
  214.             continue;
  215.         while( psz_parser && *psz_parser )
  216.         {
  217.             aout_filter_t * p_filter = NULL;
  218.             if( p_input->i_nb_filters >= AOUT_MAX_FILTERS )
  219.             {
  220.                 msg_Dbg( p_aout, "max filters reached (%d)", AOUT_MAX_FILTERS );
  221.                 break;
  222.             }
  223.             while( *psz_parser == ' ' && *psz_parser == ':' )
  224.             {
  225.                 psz_parser++;
  226.             }
  227.             if( ( psz_next = strchr( psz_parser , ':'  ) ) )
  228.             {
  229.                 *psz_next++ = '';
  230.             }
  231.             if( *psz_parser =='' )
  232.             {
  233.                 break;
  234.             }
  235.             /* Create a VLC object */
  236.             static const char typename[] = "audio filter";
  237.             p_filter = vlc_custom_create( p_aout, sizeof(*p_filter),
  238.                                           VLC_OBJECT_GENERIC, typename );
  239.             if( p_filter == NULL )
  240.             {
  241.                 msg_Err( p_aout, "cannot add user filter %s (skipped)",
  242.                          psz_parser );
  243.                 psz_parser = psz_next;
  244.                 continue;
  245.             }
  246.             vlc_object_attach( p_filter , p_aout );
  247.             p_filter->request_vout.pf_request_vout = RequestVoutFromFilter;
  248.             p_filter->request_vout.p_private = p_input;
  249.             p_filter->p_owner = malloc( sizeof(*p_filter->p_owner) );
  250.             p_filter->p_owner->p_aout  = p_aout;
  251.             p_filter->p_owner->p_input = p_input;
  252.             /* try to find the requested filter */
  253.             if( i_visual == 2 ) /* this can only be a visualization module */
  254.             {
  255.                 /* request format */
  256.                 memcpy( &p_filter->input, &chain_output_format,
  257.                         sizeof(audio_sample_format_t) );
  258.                 memcpy( &p_filter->output, &chain_output_format,
  259.                         sizeof(audio_sample_format_t) );
  260.                 p_filter->p_module = module_need( p_filter, "visualization",
  261.                                                   psz_parser, true );
  262.             }
  263.             else /* this can be a audio filter module as well as a visualization module */
  264.             {
  265.                 /* request format */
  266.                 memcpy( &p_filter->input, &chain_input_format,
  267.                         sizeof(audio_sample_format_t) );
  268.                 memcpy( &p_filter->output, &chain_output_format,
  269.                         sizeof(audio_sample_format_t) );
  270.                 p_filter->p_module = module_need( p_filter, "audio filter",
  271.                                               psz_parser, true );
  272.                 if ( p_filter->p_module == NULL )
  273.                 {
  274.                     /* if the filter requested a special format, retry */
  275.                     if ( !( AOUT_FMTS_IDENTICAL( &p_filter->input,
  276.                                                  &chain_input_format )
  277.                             && AOUT_FMTS_IDENTICAL( &p_filter->output,
  278.                                                     &chain_output_format ) ) )
  279.                     {
  280.                         aout_FormatPrepare( &p_filter->input );
  281.                         aout_FormatPrepare( &p_filter->output );
  282.                         p_filter->p_module = module_need( p_filter,
  283.                                                           "audio filter",
  284.                                                           psz_parser, true );
  285.                     }
  286.                     /* try visual filters */
  287.                     else
  288.                     {
  289.                         memcpy( &p_filter->input, &chain_output_format,
  290.                                 sizeof(audio_sample_format_t) );
  291.                         memcpy( &p_filter->output, &chain_output_format,
  292.                                 sizeof(audio_sample_format_t) );
  293.                         p_filter->p_module = module_need( p_filter,
  294.                                                           "visualization",
  295.                                                           psz_parser, true );
  296.                     }
  297.                 }
  298.             }
  299.             /* failure */
  300.             if ( p_filter->p_module == NULL )
  301.             {
  302.                 msg_Err( p_aout, "cannot add user filter %s (skipped)",
  303.                          psz_parser );
  304.                 free( p_filter->p_owner );
  305.                 vlc_object_detach( p_filter );
  306.                 vlc_object_release( p_filter );
  307.                 psz_parser = psz_next;
  308.                 continue;
  309.             }
  310.             /* complete the filter chain if necessary */
  311.             if ( !AOUT_FMTS_IDENTICAL( &chain_input_format, &p_filter->input ) )
  312.             {
  313.                 if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters,
  314.                                                  &p_input->i_nb_filters,
  315.                                                  &chain_input_format,
  316.                                                  &p_filter->input ) < 0 )
  317.                 {
  318.                     msg_Err( p_aout, "cannot add user filter %s (skipped)",
  319.                              psz_parser );
  320.                     module_unneed( p_filter, p_filter->p_module );
  321.                     free( p_filter->p_owner );
  322.                     vlc_object_detach( p_filter );
  323.                     vlc_object_release( p_filter );
  324.                     psz_parser = psz_next;
  325.                     continue;
  326.                 }
  327.             }
  328.             /* success */
  329.             p_filter->b_continuity = false;
  330.             p_input->pp_filters[p_input->i_nb_filters++] = p_filter;
  331.             memcpy( &chain_input_format, &p_filter->output,
  332.                     sizeof( audio_sample_format_t ) );
  333.             /* next filter if any */
  334.             psz_parser = psz_next;
  335.         }
  336.     }
  337.     free( psz_visual );
  338.     free( psz_filters );
  339.     free( psz_scaletempo );
  340.     /* complete the filter chain if necessary */
  341.     if ( !AOUT_FMTS_IDENTICAL( &chain_input_format, &chain_output_format ) )
  342.     {
  343.         if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters,
  344.                                          &p_input->i_nb_filters,
  345.                                          &chain_input_format,
  346.                                          &chain_output_format ) < 0 )
  347.         {
  348.             inputFailure( p_aout, p_input, "couldn't set an input pipeline" );
  349.             return -1;
  350.         }
  351.     }
  352.     /* Prepare hints for the buffer allocator. */
  353.     p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
  354.     p_input->input_alloc.i_bytes_per_sec = -1;
  355.     /* Create resamplers. */
  356.     if ( !AOUT_FMT_NON_LINEAR( &p_aout->mixer.mixer ) )
  357.     {
  358.         chain_output_format.i_rate = (__MAX(p_input->input.i_rate,
  359.                                             p_aout->mixer.mixer.i_rate)
  360.                                  * (100 + AOUT_MAX_RESAMPLING)) / 100;
  361.         if ( chain_output_format.i_rate == p_aout->mixer.mixer.i_rate )
  362.         {
  363.             /* Just in case... */
  364.             chain_output_format.i_rate++;
  365.         }
  366.         if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_resamplers,
  367.                                          &p_input->i_nb_resamplers,
  368.                                          &chain_output_format,
  369.                                          &p_aout->mixer.mixer ) < 0 )
  370.         {
  371.             inputFailure( p_aout, p_input, "couldn't set a resampler pipeline");
  372.             return -1;
  373.         }
  374.         aout_FiltersHintBuffers( p_aout, p_input->pp_resamplers,
  375.                                  p_input->i_nb_resamplers,
  376.                                  &p_input->input_alloc );
  377.         p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
  378.         /* Setup the initial rate of the resampler */
  379.         p_input->pp_resamplers[0]->input.i_rate = p_input->input.i_rate;
  380.     }
  381.     p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
  382.     p_input->p_playback_rate_filter = NULL;
  383.     for( int i = 0; i < p_input->i_nb_filters; i++ )
  384.     {
  385.         aout_filter_t *p_filter = p_input->pp_filters[i];
  386.         if( strcmp( "scaletempo", p_filter->psz_object_name ) == 0 )
  387.         {
  388.           p_input->p_playback_rate_filter = p_filter;
  389.           break;
  390.         }
  391.     }
  392.     if( ! p_input->p_playback_rate_filter && p_input->i_nb_resamplers > 0 )
  393.     {
  394.         p_input->p_playback_rate_filter = p_input->pp_resamplers[0];
  395.     }
  396.     aout_FiltersHintBuffers( p_aout, p_input->pp_filters,
  397.                              p_input->i_nb_filters,
  398.                              &p_input->input_alloc );
  399.     p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
  400.     /* i_bytes_per_sec is still == -1 if no filters */
  401.     p_input->input_alloc.i_bytes_per_sec = __MAX(
  402.                                     p_input->input_alloc.i_bytes_per_sec,
  403.                                     (int)(p_input->input.i_bytes_per_frame
  404.                                      * p_input->input.i_rate
  405.                                      / p_input->input.i_frame_length) );
  406.     ReplayGainSelect( p_aout, p_input );
  407.     /* Success */
  408.     p_input->b_error = false;
  409.     p_input->b_restart = false;
  410.     p_input->i_last_input_rate = INPUT_RATE_DEFAULT;
  411.     return 0;
  412. }
  413. /*****************************************************************************
  414.  * aout_InputDelete : delete an input
  415.  *****************************************************************************
  416.  * This function must be entered with the mixer lock.
  417.  *****************************************************************************/
  418. int aout_InputDelete( aout_instance_t * p_aout, aout_input_t * p_input )
  419. {
  420.     AOUT_ASSERT_MIXER_LOCKED;
  421.     if ( p_input->b_error )
  422.         return 0;
  423.     /* XXX We need to update b_recycle_vout before calling aout_FiltersDestroyPipeline.
  424.      * FIXME They can be a race condition if audio-visual is updated between
  425.      * aout_InputDelete and aout_InputNew.
  426.      */
  427.     char *psz_visual = var_GetString( p_aout, "audio-visual");
  428.     p_input->b_recycle_vout = psz_visual && *psz_visual;
  429.     free( psz_visual );
  430.     aout_FiltersDestroyPipeline( p_aout, p_input->pp_filters,
  431.                                  p_input->i_nb_filters );
  432.     p_input->i_nb_filters = 0;
  433.     aout_FiltersDestroyPipeline( p_aout, p_input->pp_resamplers,
  434.                                  p_input->i_nb_resamplers );
  435.     p_input->i_nb_resamplers = 0;
  436.     aout_FifoDestroy( p_aout, &p_input->fifo );
  437.     return 0;
  438. }
  439. /*****************************************************************************
  440.  * aout_InputPlay : play a buffer
  441.  *****************************************************************************
  442.  * This function must be entered with the input lock.
  443.  *****************************************************************************/
  444. /* XXX Do not activate it !! */
  445. //#define AOUT_PROCESS_BEFORE_CHEKS
  446. int aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
  447.                     aout_buffer_t * p_buffer, int i_input_rate )
  448. {
  449.     mtime_t start_date;
  450.     AOUT_ASSERT_INPUT_LOCKED;
  451.     if( p_input->b_restart )
  452.     {
  453.         aout_fifo_t fifo;
  454.         uint8_t     *p_first_byte_to_mix;
  455.         bool        b_paused;
  456.         mtime_t     i_pause_date;
  457.         aout_lock_mixer( p_aout );
  458.         aout_lock_input_fifos( p_aout );
  459.         /* A little trick to avoid loosing our input fifo and properties */
  460.         p_first_byte_to_mix = p_input->p_first_byte_to_mix;
  461.         fifo = p_input->fifo;
  462.         b_paused = p_input->b_paused;
  463.         i_pause_date = p_input->i_pause_date;
  464.         aout_FifoInit( p_aout, &p_input->fifo, p_aout->mixer.mixer.i_rate );
  465.         aout_InputDelete( p_aout, p_input );
  466.         aout_InputNew( p_aout, p_input, &p_input->request_vout );
  467.         p_input->p_first_byte_to_mix = p_first_byte_to_mix;
  468.         p_input->fifo = fifo;
  469.         p_input->b_paused = b_paused;
  470.         p_input->i_pause_date = i_pause_date;
  471.         aout_unlock_input_fifos( p_aout );
  472.         aout_unlock_mixer( p_aout );
  473.     }
  474.     if( i_input_rate != INPUT_RATE_DEFAULT && p_input->p_playback_rate_filter == NULL )
  475.     {
  476.         inputDrop( p_input, p_buffer );
  477.         return 0;
  478.     }
  479. #ifdef AOUT_PROCESS_BEFORE_CHEKS
  480.     /* Run pre-filters. */
  481.     aout_FiltersPlay( p_aout, p_input->pp_filters, p_input->i_nb_filters,
  482.                       &p_buffer );
  483.     /* Actually run the resampler now. */
  484.     if ( p_input->i_nb_resamplers > 0 )
  485.     {
  486.         const mtime_t i_date = p_buffer->start_date;
  487.         aout_FiltersPlay( p_aout, p_input->pp_resamplers,
  488.                           p_input->i_nb_resamplers,
  489.                           &p_buffer );
  490.     }
  491.     if( p_buffer->i_nb_samples <= 0 )
  492.     {
  493.         aout_BufferFree( p_buffer );
  494.         return 0;
  495.     }
  496. #endif
  497.     /* Handle input rate change, but keep drift correction */
  498.     if( i_input_rate != p_input->i_last_input_rate )
  499.     {
  500.         unsigned int * const pi_rate = &p_input->p_playback_rate_filter->input.i_rate;
  501. #define F(r,ir) ( INPUT_RATE_DEFAULT * (r) / (ir) )
  502.         const int i_delta = *pi_rate - F(p_input->input.i_rate,p_input->i_last_input_rate);
  503.         *pi_rate = F(p_input->input.i_rate + i_delta, i_input_rate);
  504. #undef F
  505.         p_input->i_last_input_rate = i_input_rate;
  506.     }
  507.     /* We don't care if someone changes the start date behind our back after
  508.      * this. We'll deal with that when pushing the buffer, and compensate
  509.      * with the next incoming buffer. */
  510.     aout_lock_input_fifos( p_aout );
  511.     start_date = aout_FifoNextStart( p_aout, &p_input->fifo );
  512.     aout_unlock_input_fifos( p_aout );
  513.     if ( start_date != 0 && start_date < mdate() )
  514.     {
  515.         /* The decoder is _very_ late. This can only happen if the user
  516.          * pauses the stream (or if the decoder is buggy, which cannot
  517.          * happen :). */
  518.         msg_Warn( p_aout, "computed PTS is out of range (%"PRId64"), "
  519.                   "clearing out", mdate() - start_date );
  520.         aout_lock_input_fifos( p_aout );
  521.         aout_FifoSet( p_aout, &p_input->fifo, 0 );
  522.         p_input->p_first_byte_to_mix = NULL;
  523.         aout_unlock_input_fifos( p_aout );
  524.         if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
  525.             msg_Warn( p_aout, "timing screwed, stopping resampling" );
  526.         inputResamplingStop( p_input );
  527.         start_date = 0;
  528.     }
  529.     if ( p_buffer->start_date < mdate() + AOUT_MIN_PREPARE_TIME )
  530.     {
  531.         /* The decoder gives us f*cked up PTS. It's its business, but we
  532.          * can't present it anyway, so drop the buffer. */
  533.         msg_Warn( p_aout, "PTS is out of range (%"PRId64"), dropping buffer",
  534.                   mdate() - p_buffer->start_date );
  535.         inputDrop( p_input, p_buffer );
  536.         inputResamplingStop( p_input );
  537.         return 0;
  538.     }
  539.     /* If the audio drift is too big then it's not worth trying to resample
  540.      * the audio. */
  541.     mtime_t i_pts_tolerance = 3 * AOUT_PTS_TOLERANCE * i_input_rate / INPUT_RATE_DEFAULT;
  542.     if ( start_date != 0 &&
  543.          ( start_date < p_buffer->start_date - i_pts_tolerance ) )
  544.     {
  545.         msg_Warn( p_aout, "audio drift is too big (%"PRId64"), clearing out",
  546.                   start_date - p_buffer->start_date );
  547.         aout_lock_input_fifos( p_aout );
  548.         aout_FifoSet( p_aout, &p_input->fifo, 0 );
  549.         p_input->p_first_byte_to_mix = NULL;
  550.         aout_unlock_input_fifos( p_aout );
  551.         if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
  552.             msg_Warn( p_aout, "timing screwed, stopping resampling" );
  553.         inputResamplingStop( p_input );
  554.         start_date = 0;
  555.     }
  556.     else if ( start_date != 0 &&
  557.               ( start_date > p_buffer->start_date + i_pts_tolerance) )
  558.     {
  559.         msg_Warn( p_aout, "audio drift is too big (%"PRId64"), dropping buffer",
  560.                   start_date - p_buffer->start_date );
  561.         inputDrop( p_input, p_buffer );
  562.         return 0;
  563.     }
  564.     if ( start_date == 0 ) start_date = p_buffer->start_date;
  565. #ifndef AOUT_PROCESS_BEFORE_CHEKS
  566.     /* Run pre-filters. */
  567.     aout_FiltersPlay( p_aout, p_input->pp_filters, p_input->i_nb_filters,
  568.                       &p_buffer );
  569. #endif
  570.     /* Run the resampler if needed.
  571.      * We first need to calculate the output rate of this resampler. */
  572.     if ( ( p_input->i_resampling_type == AOUT_RESAMPLING_NONE ) &&
  573.          ( start_date < p_buffer->start_date - AOUT_PTS_TOLERANCE
  574.            || start_date > p_buffer->start_date + AOUT_PTS_TOLERANCE ) &&
  575.          p_input->i_nb_resamplers > 0 )
  576.     {
  577.         /* Can happen in several circumstances :
  578.          * 1. A problem at the input (clock drift)
  579.          * 2. A small pause triggered by the user
  580.          * 3. Some delay in the output stage, causing a loss of lip
  581.          *    synchronization
  582.          * Solution : resample the buffer to avoid a scratch.
  583.          */
  584.         mtime_t drift = p_buffer->start_date - start_date;
  585.         p_input->i_resamp_start_date = mdate();
  586.         p_input->i_resamp_start_drift = (int)drift;
  587.         if ( drift > 0 )
  588.             p_input->i_resampling_type = AOUT_RESAMPLING_DOWN;
  589.         else
  590.             p_input->i_resampling_type = AOUT_RESAMPLING_UP;
  591.         msg_Warn( p_aout, "buffer is %"PRId64" %s, triggering %ssampling",
  592.                           drift > 0 ? drift : -drift,
  593.                           drift > 0 ? "in advance" : "late",
  594.                           drift > 0 ? "down" : "up");
  595.     }
  596.     if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
  597.     {
  598.         /* Resampling has been triggered previously (because of dates
  599.          * mismatch). We want the resampling to happen progressively so
  600.          * it isn't too audible to the listener. */
  601.         if( p_input->i_resampling_type == AOUT_RESAMPLING_UP )
  602.         {
  603.             p_input->pp_resamplers[0]->input.i_rate += 2; /* Hz */
  604.         }
  605.         else
  606.         {
  607.             p_input->pp_resamplers[0]->input.i_rate -= 2; /* Hz */
  608.         }
  609.         /* Check if everything is back to normal, in which case we can stop the
  610.          * resampling */
  611.         unsigned int i_nominal_rate =
  612.           (p_input->pp_resamplers[0] == p_input->p_playback_rate_filter)
  613.           ? INPUT_RATE_DEFAULT * p_input->input.i_rate / i_input_rate
  614.           : p_input->input.i_rate;
  615.         if( p_input->pp_resamplers[0]->input.i_rate == i_nominal_rate )
  616.         {
  617.             p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
  618.             msg_Warn( p_aout, "resampling stopped after %"PRIi64" usec "
  619.                       "(drift: %"PRIi64")",
  620.                       mdate() - p_input->i_resamp_start_date,
  621.                       p_buffer->start_date - start_date);
  622.         }
  623.         else if( abs( (int)(p_buffer->start_date - start_date) ) <
  624.                  abs( p_input->i_resamp_start_drift ) / 2 )
  625.         {
  626.             /* if we reduced the drift from half, then it is time to switch
  627.              * back the resampling direction. */
  628.             if( p_input->i_resampling_type == AOUT_RESAMPLING_UP )
  629.                 p_input->i_resampling_type = AOUT_RESAMPLING_DOWN;
  630.             else
  631.                 p_input->i_resampling_type = AOUT_RESAMPLING_UP;
  632.             p_input->i_resamp_start_drift = 0;
  633.         }
  634.         else if( p_input->i_resamp_start_drift &&
  635.                  ( abs( (int)(p_buffer->start_date - start_date) ) >
  636.                    abs( p_input->i_resamp_start_drift ) * 3 / 2 ) )
  637.         {
  638.             /* If the drift is increasing and not decreasing, than something
  639.              * is bad. We'd better stop the resampling right now. */
  640.             msg_Warn( p_aout, "timing screwed, stopping resampling" );
  641.             inputResamplingStop( p_input );
  642.         }
  643.     }
  644. #ifndef AOUT_PROCESS_BEFORE_CHEKS
  645.     /* Actually run the resampler now. */
  646.     if ( p_input->i_nb_resamplers > 0 )
  647.     {
  648.         aout_FiltersPlay( p_aout, p_input->pp_resamplers,
  649.                           p_input->i_nb_resamplers,
  650.                           &p_buffer );
  651.     }
  652.     if( p_buffer->i_nb_samples <= 0 )
  653.     {
  654.         aout_BufferFree( p_buffer );
  655.         return 0;
  656.     }
  657. #endif
  658.     /* Adding the start date will be managed by aout_FifoPush(). */
  659.     p_buffer->end_date = start_date +
  660.         (p_buffer->end_date - p_buffer->start_date);
  661.     p_buffer->start_date = start_date;
  662.     aout_lock_input_fifos( p_aout );
  663.     aout_FifoPush( p_aout, &p_input->fifo, p_buffer );
  664.     aout_unlock_input_fifos( p_aout );
  665.     return 0;
  666. }
  667. /*****************************************************************************
  668.  * static functions
  669.  *****************************************************************************/
  670. static void inputFailure( aout_instance_t * p_aout, aout_input_t * p_input,
  671.                           const char * psz_error_message )
  672. {
  673.     /* error message */
  674.     msg_Err( p_aout, "%s", psz_error_message );
  675.     /* clean up */
  676.     aout_FiltersDestroyPipeline( p_aout, p_input->pp_filters,
  677.                                  p_input->i_nb_filters );
  678.     aout_FiltersDestroyPipeline( p_aout, p_input->pp_resamplers,
  679.                                  p_input->i_nb_resamplers );
  680.     aout_FifoDestroy( p_aout, &p_input->fifo );
  681.     var_Destroy( p_aout, "visual" );
  682.     var_Destroy( p_aout, "equalizer" );
  683.     var_Destroy( p_aout, "audio-filter" );
  684.     var_Destroy( p_aout, "audio-visual" );
  685.     var_Destroy( p_aout, "audio-replay-gain-mode" );
  686.     var_Destroy( p_aout, "audio-replay-gain-default" );
  687.     var_Destroy( p_aout, "audio-replay-gain-preamp" );
  688.     var_Destroy( p_aout, "audio-replay-gain-peak-protection" );
  689.     /* error flag */
  690.     p_input->b_error = 1;
  691. }
  692. static void inputDrop( aout_input_t *p_input, aout_buffer_t *p_buffer )
  693. {
  694.     aout_BufferFree( p_buffer );
  695.     p_input->i_buffer_lost++;
  696. }
  697. static void inputResamplingStop( aout_input_t *p_input )
  698. {
  699.     p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
  700.     if( p_input->i_nb_resamplers != 0 )
  701.     {
  702.         p_input->pp_resamplers[0]->input.i_rate =
  703.             ( p_input->pp_resamplers[0] == p_input->p_playback_rate_filter )
  704.             ? INPUT_RATE_DEFAULT * p_input->input.i_rate / p_input->i_last_input_rate
  705.             : p_input->input.i_rate;
  706.         p_input->pp_resamplers[0]->b_continuity = false;
  707.     }
  708. }
  709. static vout_thread_t *RequestVout( void *p_private,
  710.                                    vout_thread_t *p_vout, video_format_t *p_fmt, bool b_recycle )
  711. {
  712.     aout_instance_t *p_aout = p_private;
  713.     VLC_UNUSED(b_recycle);
  714.     return vout_Request( p_aout, p_vout, p_fmt );
  715. }
  716. static vout_thread_t *RequestVoutFromFilter( void *p_private,
  717.                                             vout_thread_t *p_vout, video_format_t *p_fmt, bool b_recycle )
  718. {
  719.     aout_input_t *p_input = p_private;
  720.     aout_request_vout_t *p_request = &p_input->request_vout;
  721.     return p_request->pf_request_vout( p_request->p_private,
  722.                                        p_vout, p_fmt, p_input->b_recycle_vout && b_recycle );
  723. }
  724. static int ChangeFiltersString( aout_instance_t * p_aout, const char* psz_variable,
  725.                                  const char *psz_name, bool b_add )
  726. {
  727.     return AoutChangeFilterString( VLC_OBJECT(p_aout), p_aout,
  728.                                    psz_variable, psz_name, b_add ) ? 1 : 0;
  729. }
  730. static int VisualizationCallback( vlc_object_t *p_this, char const *psz_cmd,
  731.                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
  732. {
  733.     aout_instance_t *p_aout = (aout_instance_t *)p_this;
  734.     char *psz_mode = newval.psz_string;
  735.     (void)psz_cmd; (void)oldval; (void)p_data;
  736.     if( !psz_mode || !*psz_mode )
  737.     {
  738.         ChangeFiltersString( p_aout, "audio-visual", "goom", false );
  739.         ChangeFiltersString( p_aout, "audio-visual", "visual", false );
  740.         ChangeFiltersString( p_aout, "audio-visual", "galaktos", false );
  741.     }
  742.     else
  743.     {
  744.         if( !strcmp( "goom", psz_mode ) )
  745.         {
  746.             ChangeFiltersString( p_aout, "audio-visual", "visual", false );
  747.             ChangeFiltersString( p_aout, "audio-visual", "goom", true );
  748.             ChangeFiltersString( p_aout, "audio-visual", "galaktos", false);
  749.         }
  750.         else if( !strcmp( "galaktos", psz_mode ) )
  751.         {
  752.             ChangeFiltersString( p_aout, "audio-visual", "visual", false );
  753.             ChangeFiltersString( p_aout, "audio-visual", "goom", false );
  754.             ChangeFiltersString( p_aout, "audio-visual", "galaktos", true );
  755.         }
  756.         else
  757.         {
  758.             var_Create( p_aout, "effect-list", VLC_VAR_STRING );
  759.             var_SetString( p_aout, "effect-list", psz_mode );
  760.             ChangeFiltersString( p_aout, "audio-visual", "goom", false );
  761.             ChangeFiltersString( p_aout, "audio-visual", "visual", true );
  762.             ChangeFiltersString( p_aout, "audio-visual", "galaktos", false);
  763.         }
  764.     }
  765.     /* That sucks */
  766.     AoutInputsMarkToRestart( p_aout );
  767.     return VLC_SUCCESS;
  768. }
  769. static int EqualizerCallback( vlc_object_t *p_this, char const *psz_cmd,
  770.                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
  771. {
  772.     aout_instance_t *p_aout = (aout_instance_t *)p_this;
  773.     char *psz_mode = newval.psz_string;
  774.     int i_ret;
  775.     (void)psz_cmd; (void)oldval; (void)p_data;
  776.     if( !psz_mode || !*psz_mode )
  777.     {
  778.         i_ret = ChangeFiltersString( p_aout, "audio-filter", "equalizer",
  779.                                      false );
  780.     }
  781.     else
  782.     {
  783.         var_Create( p_aout, "equalizer-preset", VLC_VAR_STRING );
  784.         var_SetString( p_aout, "equalizer-preset", psz_mode );
  785.         i_ret = ChangeFiltersString( p_aout, "audio-filter", "equalizer",
  786.                                      true );
  787.     }
  788.     /* That sucks */
  789.     if( i_ret == 1 )
  790.         AoutInputsMarkToRestart( p_aout );
  791.     return VLC_SUCCESS;
  792. }
  793. static int ReplayGainCallback( vlc_object_t *p_this, char const *psz_cmd,
  794.                                vlc_value_t oldval, vlc_value_t newval, void *p_data )
  795. {
  796.     VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
  797.     VLC_UNUSED(newval); VLC_UNUSED(p_data);
  798.     aout_instance_t *p_aout = (aout_instance_t *)p_this;
  799.     int i;
  800.     aout_lock_mixer( p_aout );
  801.     for( i = 0; i < p_aout->i_nb_inputs; i++ )
  802.         ReplayGainSelect( p_aout, p_aout->pp_inputs[i] );
  803.     /* Restart the mixer (a trivial mixer may be in use) */
  804.     aout_MixerMultiplierSet( p_aout, p_aout->mixer.f_multiplier );
  805.     aout_unlock_mixer( p_aout );
  806.     return VLC_SUCCESS;
  807. }
  808. static void ReplayGainSelect( aout_instance_t *p_aout, aout_input_t *p_input )
  809. {
  810.     char *psz_replay_gain = var_GetNonEmptyString( p_aout,
  811.                                                    "audio-replay-gain-mode" );
  812.     int i_mode;
  813.     int i_use;
  814.     float f_gain;
  815.     p_input->f_multiplier = 1.0;
  816.     if( !psz_replay_gain )
  817.         return;
  818.     /* Find select mode */
  819.     if( !strcmp( psz_replay_gain, "track" ) )
  820.         i_mode = AUDIO_REPLAY_GAIN_TRACK;
  821.     else if( !strcmp( psz_replay_gain, "album" ) )
  822.         i_mode = AUDIO_REPLAY_GAIN_ALBUM;
  823.     else
  824.         i_mode = AUDIO_REPLAY_GAIN_MAX;
  825.     /* If the select mode is not available, prefer the other one */
  826.     i_use = i_mode;
  827.     if( i_use != AUDIO_REPLAY_GAIN_MAX && !p_input->replay_gain.pb_gain[i_use] )
  828.     {
  829.         for( i_use = 0; i_use < AUDIO_REPLAY_GAIN_MAX; i_use++ )
  830.         {
  831.             if( p_input->replay_gain.pb_gain[i_use] )
  832.                 break;
  833.         }
  834.     }
  835.     /* */
  836.     if( i_use != AUDIO_REPLAY_GAIN_MAX )
  837.         f_gain = p_input->replay_gain.pf_gain[i_use] + var_GetFloat( p_aout, "audio-replay-gain-preamp" );
  838.     else if( i_mode != AUDIO_REPLAY_GAIN_MAX )
  839.         f_gain = var_GetFloat( p_aout, "audio-replay-gain-default" );
  840.     else
  841.         f_gain = 0.0;
  842.     p_input->f_multiplier = pow( 10.0, f_gain / 20.0 );
  843.     /* */
  844.     if( p_input->replay_gain.pb_peak[i_use] &&
  845.         var_GetBool( p_aout, "audio-replay-gain-peak-protection" ) &&
  846.         p_input->replay_gain.pf_peak[i_use] * p_input->f_multiplier > 1.0 )
  847.     {
  848.         p_input->f_multiplier = 1.0f / p_input->replay_gain.pf_peak[i_use];
  849.     }
  850.     free( psz_replay_gain );
  851. }