/***************************************************************************** * aout_InputNew : allocate a new input and rework the filter pipeline *****************************************************************************/ int aout_InputNew( aout_instance_t * p_aout, aout_input_t * p_input, const aout_request_vout_t *p_request_vout ) { audio_sample_format_t chain_input_format; audio_sample_format_t chain_output_format; vlc_value_t val, text; char *psz_filters, *psz_visual, *psz_scaletempo; int i_visual; aout_FormatPrint( p_aout, "input", &p_input->input ); p_input->i_nb_resamplers = p_input->i_nb_filters = 0; /* Prepare FIFO. */ aout_FifoInit( p_aout, &p_input->mixer.fifo, p_aout->mixer_format.i_rate ); p_input->mixer.begin = NULL; /* */ if( p_request_vout ) { p_input->request_vout = *p_request_vout; } else { p_input->request_vout.pf_request_vout = RequestVout; p_input->request_vout.p_private = p_aout; } /* Prepare format structure */ chain_input_format = p_input->input; chain_output_format = p_aout->mixer_format; 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 ) { var_Create( p_aout, "visual", VLC_VAR_STRING | VLC_VAR_HASCHOICE ); text.psz_string = _("Visualizations"); var_Change( p_aout, "visual", VLC_VAR_SETTEXT, &text, NULL ); val.psz_string = (char*)""; text.psz_string = _("Disable"); var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text ); val.psz_string = (char*)"spectrometer"; text.psz_string = _("Spectrometer"); var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text ); val.psz_string = (char*)"scope"; text.psz_string = _("Scope"); var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text ); val.psz_string = (char*)"spectrum"; text.psz_string = _("Spectrum"); var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text ); val.psz_string = (char*)"vuMeter"; text.psz_string = _("Vu meter"); var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text ); /* Look for goom plugin */ if( module_exists( "goom" ) ) { val.psz_string = (char*)"goom"; text.psz_string = (char*)"Goom"; var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text ); } /* Look for libprojectM plugin */ if( module_exists( "projectm" ) ) { val.psz_string = (char*)"projectm"; text.psz_string = (char*)"projectM"; var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text ); } if( var_Get( p_aout, "effect-list", &val ) == VLC_SUCCESS ) { var_SetString( p_aout, "visual", val.psz_string ); free( val.psz_string ); } var_AddCallback( p_aout, "visual", VisualizationCallback, NULL ); } if( var_Type( p_aout, "equalizer" ) == 0 ) { module_config_t *p_config; int i; p_config = config_FindConfig( VLC_OBJECT(p_aout), "equalizer-preset" ); if( p_config && p_config->i_list ) { var_Create( p_aout, "equalizer", VLC_VAR_STRING | VLC_VAR_HASCHOICE ); text.psz_string = _("Equalizer"); var_Change( p_aout, "equalizer", VLC_VAR_SETTEXT, &text, NULL ); val.psz_string = (char*)""; text.psz_string = _("Disable"); var_Change( p_aout, "equalizer", VLC_VAR_ADDCHOICE, &val, &text ); for( i = 0; i < p_config->i_list; i++ ) { val.psz_string = (char *)p_config->ppsz_list[i]; text.psz_string = (char *)p_config->ppsz_list_text[i]; var_Change( p_aout, "equalizer", VLC_VAR_ADDCHOICE, &val, &text ); } var_AddCallback( p_aout, "equalizer", EqualizerCallback, NULL ); } } if( var_Type( p_aout, "audio-filter" ) == 0 ) { var_Create( p_aout, "audio-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); text.psz_string = _("Audio filters"); var_Change( p_aout, "audio-filter", VLC_VAR_SETTEXT, &text, NULL ); } if( var_Type( p_aout, "audio-visual" ) == 0 ) { var_Create( p_aout, "audio-visual", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); text.psz_string = _("Audio visualizations"); var_Change( p_aout, "audio-visual", VLC_VAR_SETTEXT, &text, NULL ); } if( var_Type( p_aout, "audio-replay-gain-mode" ) == 0 ) { module_config_t *p_config; int i; p_config = config_FindConfig( VLC_OBJECT(p_aout), "audio-replay-gain-mode" ); if( p_config && p_config->i_list ) { var_Create( p_aout, "audio-replay-gain-mode", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); text.psz_string = _("Replay gain"); var_Change( p_aout, "audio-replay-gain-mode", VLC_VAR_SETTEXT, &text, NULL ); for( i = 0; i < p_config->i_list; i++ ) { val.psz_string = (char *)p_config->ppsz_list[i]; text.psz_string = (char *)p_config->ppsz_list_text[i]; var_Change( p_aout, "audio-replay-gain-mode", VLC_VAR_ADDCHOICE, &val, &text ); } var_AddCallback( p_aout, "audio-replay-gain-mode", ReplayGainCallback, NULL ); } } if( var_Type( p_aout, "audio-replay-gain-preamp" ) == 0 ) { var_Create( p_aout, "audio-replay-gain-preamp", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT ); } if( var_Type( p_aout, "audio-replay-gain-default" ) == 0 ) { var_Create( p_aout, "audio-replay-gain-default", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT ); } if( var_Type( p_aout, "audio-replay-gain-peak-protection" ) == 0 ) { var_Create( p_aout, "audio-replay-gain-peak-protection", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); } if( var_Type( p_aout, "audio-time-stretch" ) == 0 ) { var_Create( p_aout, "audio-time-stretch", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); } psz_filters = var_GetString( p_aout, "audio-filter" ); psz_visual = var_GetString( p_aout, "audio-visual"); psz_scaletempo = var_GetBool( p_aout, "audio-time-stretch" ) ? strdup( "scaletempo" ) : NULL; p_input->b_recycle_vout = psz_visual && *psz_visual; /* parse user filter lists */ char *const ppsz_array[] = { psz_scaletempo, psz_filters, psz_visual }; p_input->p_playback_rate_filter = NULL; for( i_visual = 0; i_visual < 3 && !AOUT_FMT_NON_LINEAR(&chain_output_format); i_visual++ ) { char *psz_next = NULL; char *psz_parser = ppsz_array[i_visual]; if( psz_parser == NULL || !*psz_parser ) continue; while( psz_parser && *psz_parser ) { filter_t * p_filter = NULL; if( p_input->i_nb_filters >= AOUT_MAX_FILTERS ) { msg_Dbg( p_aout, "max filters reached (%d)", AOUT_MAX_FILTERS ); break; } while( *psz_parser == ' ' && *psz_parser == ':' ) { psz_parser++; } if( ( psz_next = strchr( psz_parser , ':' ) ) ) { *psz_next++ = '\0'; } if( *psz_parser =='\0' ) { break; } /* Create a VLC object */ static const char typename[] = "audio filter"; p_filter = vlc_custom_create( p_aout, sizeof(*p_filter), VLC_OBJECT_GENERIC, typename ); if( p_filter == NULL ) { msg_Err( p_aout, "cannot add user filter %s (skipped)", psz_parser ); psz_parser = psz_next; continue; } vlc_object_attach( p_filter , p_aout ); p_filter->p_owner = malloc( sizeof(*p_filter->p_owner) ); p_filter->p_owner->p_aout = p_aout; p_filter->p_owner->p_input = p_input; /* request format */ memcpy( &p_filter->fmt_in.audio, &chain_output_format, sizeof(audio_sample_format_t) ); p_filter->fmt_in.i_codec = chain_output_format.i_format; memcpy( &p_filter->fmt_out.audio, &chain_output_format, sizeof(audio_sample_format_t) ); p_filter->fmt_out.i_codec = chain_output_format.i_format; p_filter->pf_audio_buffer_new = aout_FilterBufferNew; /* try to find the requested filter */ if( i_visual == 2 ) /* this can only be a visualization module */ { p_filter->p_module = module_need( p_filter, "visualization2", psz_parser, true ); } else /* this can be a audio filter module as well as a visualization module */ { p_filter->p_module = module_need( p_filter, "audio filter", psz_parser, true ); if ( p_filter->p_module == NULL ) { /* if the filter requested a special format, retry */ if ( !( AOUT_FMTS_IDENTICAL( &p_filter->fmt_in.audio, &chain_input_format ) && AOUT_FMTS_IDENTICAL( &p_filter->fmt_out.audio, &chain_output_format ) ) ) { aout_FormatPrepare( &p_filter->fmt_in.audio ); aout_FormatPrepare( &p_filter->fmt_out.audio ); p_filter->p_module = module_need( p_filter, "audio filter", psz_parser, true ); } /* try visual filters */ else { memcpy( &p_filter->fmt_in.audio, &chain_output_format, sizeof(audio_sample_format_t) ); memcpy( &p_filter->fmt_out.audio, &chain_output_format, sizeof(audio_sample_format_t) ); p_filter->p_module = module_need( p_filter, "visualization2", psz_parser, true ); } } } /* failure */ if ( p_filter->p_module == NULL ) { msg_Err( p_aout, "cannot add user filter %s (skipped)", psz_parser ); free( p_filter->p_owner ); vlc_object_release( p_filter ); psz_parser = psz_next; continue; } /* complete the filter chain if necessary */ if ( !AOUT_FMTS_IDENTICAL( &chain_input_format, &p_filter->fmt_in.audio ) ) { if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters, &p_input->i_nb_filters, &chain_input_format, &p_filter->fmt_in.audio ) < 0 ) { msg_Err( p_aout, "cannot add user filter %s (skipped)", psz_parser ); module_unneed( p_filter, p_filter->p_module ); free( p_filter->p_owner ); vlc_object_release( p_filter ); psz_parser = psz_next; continue; } } /* success */ p_input->pp_filters[p_input->i_nb_filters++] = p_filter; memcpy( &chain_input_format, &p_filter->fmt_out.audio, sizeof( audio_sample_format_t ) ); if( i_visual == 0 ) /* scaletempo */ p_input->p_playback_rate_filter = p_filter; /* next filter if any */ psz_parser = psz_next; } } free( psz_visual ); free( psz_filters ); free( psz_scaletempo ); /* complete the filter chain if necessary */ if ( !AOUT_FMTS_IDENTICAL( &chain_input_format, &chain_output_format ) ) { 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.b_alloc = true; p_input->input_alloc.i_bytes_per_sec = -1; /* Create resamplers. */ if ( !AOUT_FMT_NON_LINEAR( &p_aout->mixer_format ) ) { chain_output_format.i_rate = (__MAX(p_input->input.i_rate, p_aout->mixer_format.i_rate) * (100 + AOUT_MAX_RESAMPLING)) / 100; if ( chain_output_format.i_rate == p_aout->mixer_format.i_rate ) { /* Just in case... */ chain_output_format.i_rate++; } if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_resamplers, &p_input->i_nb_resamplers, &chain_output_format, &p_aout->mixer_format ) < 0 ) { 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.b_alloc = true; /* Setup the initial rate of the resampler */ p_input->pp_resamplers[0]->fmt_in.audio.i_rate = p_input->input.i_rate; } p_input->i_resampling_type = AOUT_RESAMPLING_NONE; if( ! p_input->p_playback_rate_filter && p_input->i_nb_resamplers > 0 ) { p_input->p_playback_rate_filter = p_input->pp_resamplers[0]; } aout_FiltersHintBuffers( p_aout, p_input->pp_filters, p_input->i_nb_filters, &p_input->input_alloc ); p_input->input_alloc.b_alloc = true; /* i_bytes_per_sec is still == -1 if no filters */ p_input->input_alloc.i_bytes_per_sec = __MAX( p_input->input_alloc.i_bytes_per_sec, (int)(p_input->input.i_bytes_per_frame * p_input->input.i_rate / p_input->input.i_frame_length) ); ReplayGainSelect( p_aout, p_input ); /* Success */ p_input->b_error = false; p_input->i_last_input_rate = INPUT_RATE_DEFAULT; return 0; }
/***************************************************************************** * aout_OutputNew : allocate a new output and rework the filter pipeline ***************************************************************************** * This function is entered with the mixer lock. *****************************************************************************/ int aout_OutputNew( audio_output_t *p_aout, const audio_sample_format_t * p_format ) { aout_owner_t *owner = aout_owner (p_aout); aout_assert_locked( p_aout ); p_aout->format = *p_format; aout_FormatPrepare( &p_aout->format ); /* Find the best output plug-in. */ owner->module = module_need (p_aout, "audio output", "$aout", false); if (owner->module == NULL) { msg_Err( p_aout, "no suitable audio output module" ); return -1; } if ( var_Type( p_aout, "audio-channels" ) == (VLC_VAR_INTEGER | VLC_VAR_HASCHOICE) ) { /* The user may have selected a different channels configuration. */ switch( var_InheritInteger( p_aout, "audio-channels" ) ) { case AOUT_VAR_CHAN_RSTEREO: p_aout->format.i_original_channels |= AOUT_CHAN_REVERSESTEREO; break; case AOUT_VAR_CHAN_STEREO: p_aout->format.i_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; break; case AOUT_VAR_CHAN_LEFT: p_aout->format.i_original_channels = AOUT_CHAN_LEFT; break; case AOUT_VAR_CHAN_RIGHT: p_aout->format.i_original_channels = AOUT_CHAN_RIGHT; break; case AOUT_VAR_CHAN_DOLBYS: p_aout->format.i_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_DOLBYSTEREO; break; } } else if ( p_aout->format.i_physical_channels == AOUT_CHAN_CENTER && (p_aout->format.i_original_channels & AOUT_CHAN_PHYSMASK) == (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT) ) { vlc_value_t val, text; /* Mono - create the audio-channels variable. */ var_Create( p_aout, "audio-channels", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE ); text.psz_string = _("Audio Channels"); var_Change( p_aout, "audio-channels", VLC_VAR_SETTEXT, &text, NULL ); val.i_int = AOUT_VAR_CHAN_STEREO; text.psz_string = _("Stereo"); var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text ); val.i_int = AOUT_VAR_CHAN_LEFT; text.psz_string = _("Left"); var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text ); val.i_int = AOUT_VAR_CHAN_RIGHT; text.psz_string = _("Right"); var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text ); if ( p_aout->format.i_original_channels & AOUT_CHAN_DUALMONO ) { /* Go directly to the left channel. */ p_aout->format.i_original_channels = AOUT_CHAN_LEFT; var_SetInteger( p_aout, "audio-channels", AOUT_VAR_CHAN_LEFT ); } var_AddCallback( p_aout, "audio-channels", aout_ChannelsRestart, NULL ); } else if ( p_aout->format.i_physical_channels == (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT) && (p_aout->format.i_original_channels & (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)) ) { vlc_value_t val, text; /* Stereo - create the audio-channels variable. */ var_Create( p_aout, "audio-channels", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE ); text.psz_string = _("Audio Channels"); var_Change( p_aout, "audio-channels", VLC_VAR_SETTEXT, &text, NULL ); if ( p_aout->format.i_original_channels & AOUT_CHAN_DOLBYSTEREO ) { val.i_int = AOUT_VAR_CHAN_DOLBYS; text.psz_string = _("Dolby Surround"); } else { val.i_int = AOUT_VAR_CHAN_STEREO; text.psz_string = _("Stereo"); } var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text ); val.i_int = AOUT_VAR_CHAN_LEFT; text.psz_string = _("Left"); var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text ); val.i_int = AOUT_VAR_CHAN_RIGHT; text.psz_string = _("Right"); var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text ); val.i_int = AOUT_VAR_CHAN_RSTEREO; text.psz_string=_("Reverse stereo"); var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text ); if ( p_aout->format.i_original_channels & AOUT_CHAN_DUALMONO ) { /* Go directly to the left channel. */ p_aout->format.i_original_channels = AOUT_CHAN_LEFT; var_SetInteger( p_aout, "audio-channels", AOUT_VAR_CHAN_LEFT ); } var_AddCallback( p_aout, "audio-channels", aout_ChannelsRestart, NULL ); } var_TriggerCallback( p_aout, "intf-change" ); aout_FormatPrepare( &p_aout->format ); aout_FormatPrint( p_aout, "output", &p_aout->format ); /* Choose the mixer format. */ owner->mixer_format = p_aout->format; if (!AOUT_FMT_LINEAR(&p_aout->format)) owner->mixer_format.i_format = p_format->i_format; else /* Most audio filters can only deal with single-precision, * so lets always use that when hardware supports floating point. */ if( HAVE_FPU ) owner->mixer_format.i_format = VLC_CODEC_FL32; else /* Otherwise, audio filters will not work. Use fixed-point if the input has * more than 16-bits depth. */ if( p_format->i_bitspersample > 16 || !AOUT_FMT_LINEAR(p_format)) owner->mixer_format.i_format = VLC_CODEC_FI32; else /* Fallback to 16-bits. This avoids pointless conversion to and from * 32-bits samples for the sole purpose of software mixing. */ owner->mixer_format.i_format = VLC_CODEC_S16N; aout_FormatPrepare (&owner->mixer_format); aout_FormatPrint (p_aout, "mixer", &owner->mixer_format); /* Create filters. */ owner->nb_filters = 0; if (aout_FiltersCreatePipeline (p_aout, owner->filters, &owner->nb_filters, &owner->mixer_format, &p_aout->format) < 0) { msg_Err( p_aout, "couldn't create audio output pipeline" ); module_unneed (p_aout, owner->module); owner->module = NULL; return -1; } return 0; }
/***************************************************************************** * aout_OutputNew : allocate a new output and rework the filter pipeline ***************************************************************************** * This function is entered with the mixer lock. *****************************************************************************/ int aout_OutputNew( aout_instance_t * p_aout, audio_sample_format_t * p_format ) { /* Retrieve user defaults. */ int i_rate = var_InheritInteger( p_aout, "aout-rate" ); vlc_value_t val, text; /* kludge to avoid a fpu error when rate is 0... */ if( i_rate == 0 ) i_rate = -1; memcpy( &p_aout->output.output, p_format, sizeof(audio_sample_format_t) ); if ( i_rate != -1 ) p_aout->output.output.i_rate = i_rate; aout_FormatPrepare( &p_aout->output.output ); /* Find the best output plug-in. */ p_aout->output.p_module = module_need( p_aout, "audio output", "$aout", false ); if ( p_aout->output.p_module == NULL ) { msg_Err( p_aout, "no suitable audio output module" ); return -1; } if ( var_Type( p_aout, "audio-channels" ) == (VLC_VAR_INTEGER | VLC_VAR_HASCHOICE) ) { /* The user may have selected a different channels configuration. */ var_Get( p_aout, "audio-channels", &val ); if ( val.i_int == AOUT_VAR_CHAN_RSTEREO ) { p_aout->output.output.i_original_channels |= AOUT_CHAN_REVERSESTEREO; } else if ( val.i_int == AOUT_VAR_CHAN_STEREO ) { p_aout->output.output.i_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; } else if ( val.i_int == AOUT_VAR_CHAN_LEFT ) { p_aout->output.output.i_original_channels = AOUT_CHAN_LEFT; } else if ( val.i_int == AOUT_VAR_CHAN_RIGHT ) { p_aout->output.output.i_original_channels = AOUT_CHAN_RIGHT; } else if ( val.i_int == AOUT_VAR_CHAN_DOLBYS ) { p_aout->output.output.i_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_DOLBYSTEREO; } } else if ( p_aout->output.output.i_physical_channels == AOUT_CHAN_CENTER && (p_aout->output.output.i_original_channels & AOUT_CHAN_PHYSMASK) == (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT) ) { /* Mono - create the audio-channels variable. */ var_Create( p_aout, "audio-channels", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE ); text.psz_string = _("Audio Channels"); var_Change( p_aout, "audio-channels", VLC_VAR_SETTEXT, &text, NULL ); val.i_int = AOUT_VAR_CHAN_STEREO; text.psz_string = _("Stereo"); var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text ); val.i_int = AOUT_VAR_CHAN_LEFT; text.psz_string = _("Left"); var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text ); val.i_int = AOUT_VAR_CHAN_RIGHT; text.psz_string = _("Right"); var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text ); if ( p_aout->output.output.i_original_channels & AOUT_CHAN_DUALMONO ) { /* Go directly to the left channel. */ p_aout->output.output.i_original_channels = AOUT_CHAN_LEFT; var_SetInteger( p_aout, "audio-channels", AOUT_VAR_CHAN_LEFT ); } var_AddCallback( p_aout, "audio-channels", aout_ChannelsRestart, NULL ); } else if ( p_aout->output.output.i_physical_channels == (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT) && (p_aout->output.output.i_original_channels & (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)) ) { /* Stereo - create the audio-channels variable. */ var_Create( p_aout, "audio-channels", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE ); text.psz_string = _("Audio Channels"); var_Change( p_aout, "audio-channels", VLC_VAR_SETTEXT, &text, NULL ); if ( p_aout->output.output.i_original_channels & AOUT_CHAN_DOLBYSTEREO ) { val.i_int = AOUT_VAR_CHAN_DOLBYS; text.psz_string = _("Dolby Surround"); } else { val.i_int = AOUT_VAR_CHAN_STEREO; text.psz_string = _("Stereo"); } var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text ); val.i_int = AOUT_VAR_CHAN_LEFT; text.psz_string = _("Left"); var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text ); val.i_int = AOUT_VAR_CHAN_RIGHT; text.psz_string = _("Right"); var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text ); val.i_int = AOUT_VAR_CHAN_RSTEREO; text.psz_string=_("Reverse stereo"); var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text ); if ( p_aout->output.output.i_original_channels & AOUT_CHAN_DUALMONO ) { /* Go directly to the left channel. */ p_aout->output.output.i_original_channels = AOUT_CHAN_LEFT; var_SetInteger( p_aout, "audio-channels", AOUT_VAR_CHAN_LEFT ); } var_AddCallback( p_aout, "audio-channels", aout_ChannelsRestart, NULL ); } var_SetBool( p_aout, "intf-change", true ); aout_FormatPrepare( &p_aout->output.output ); aout_lock_output_fifo( p_aout ); /* Prepare FIFO. */ aout_FifoInit( p_aout, &p_aout->output.fifo, p_aout->output.output.i_rate ); aout_unlock_output_fifo( p_aout ); aout_FormatPrint( p_aout, "output", &p_aout->output.output ); /* Calculate the resulting mixer output format. */ p_aout->mixer_format = p_aout->output.output; if ( !AOUT_FMT_NON_LINEAR(&p_aout->output.output) ) { /* Non-S/PDIF mixer only deals with float32 or fixed32. */ p_aout->mixer_format.i_format = HAVE_FPU ? VLC_CODEC_FL32 : VLC_CODEC_FI32; aout_FormatPrepare( &p_aout->mixer_format ); } else { p_aout->mixer_format.i_format = p_format->i_format; } aout_FormatPrint( p_aout, "mixer", &p_aout->mixer_format ); /* 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_format, &p_aout->output.output ) < 0 ) { msg_Err( p_aout, "couldn't create audio output pipeline" ); module_unneed( p_aout, p_aout->output.p_module ); return -1; } /* Prepare hints for the buffer allocator. */ p_aout->mixer_allocation.b_alloc = true; p_aout->mixer_allocation.i_bytes_per_sec = p_aout->mixer_format.i_bytes_per_frame * p_aout->mixer_format.i_rate / p_aout->mixer_format.i_frame_length; aout_FiltersHintBuffers( p_aout, p_aout->output.pp_filters, p_aout->output.i_nb_filters, &p_aout->mixer_allocation ); p_aout->output.b_error = 0; return 0; }
/***************************************************************************** * 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 chain_input_format; audio_sample_format_t chain_output_format; vlc_value_t val, text; char * psz_filters, *psz_visual; int i_visual; 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( &chain_input_format, &p_input->input, sizeof(audio_sample_format_t) ); 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 ) { module_t *p_module; var_Create( p_aout, "visual", VLC_VAR_STRING | VLC_VAR_HASCHOICE ); text.psz_string = _("Visualizations"); var_Change( p_aout, "visual", VLC_VAR_SETTEXT, &text, NULL ); val.psz_string = ""; text.psz_string = _("Disable"); var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text ); val.psz_string = "spectrometer"; text.psz_string = _("Spectrometer"); var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text ); val.psz_string = "scope"; text.psz_string = _("Scope"); var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text ); val.psz_string = "spectrum"; text.psz_string = _("Spectrum"); var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text ); /* Look for goom plugin */ p_module = config_FindModule( VLC_OBJECT(p_aout), "goom" ); if( p_module ) { val.psz_string = "goom"; text.psz_string = "Goom"; var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text ); } /* Look for galaktos plugin */ p_module = config_FindModule( VLC_OBJECT(p_aout), "galaktos" ); if( p_module ) { val.psz_string = "galaktos"; text.psz_string = "GaLaktos"; var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text ); } if( var_Get( p_aout, "effect-list", &val ) == VLC_SUCCESS ) { var_Set( p_aout, "visual", val ); if( val.psz_string ) free( val.psz_string ); } var_AddCallback( p_aout, "visual", VisualizationCallback, NULL ); } if( var_Type( p_aout, "equalizer" ) == 0 ) { module_config_t *p_config; int i; p_config = config_FindConfig( VLC_OBJECT(p_aout), "equalizer-preset" ); if( p_config && p_config->i_list ) { var_Create( p_aout, "equalizer", VLC_VAR_STRING | VLC_VAR_HASCHOICE ); text.psz_string = _("Equalizer"); var_Change( p_aout, "equalizer", VLC_VAR_SETTEXT, &text, NULL ); val.psz_string = ""; text.psz_string = _("Disable"); var_Change( p_aout, "equalizer", VLC_VAR_ADDCHOICE, &val, &text ); for( i = 0; i < p_config->i_list; i++ ) { val.psz_string = p_config->ppsz_list[i]; text.psz_string = p_config->ppsz_list_text[i]; var_Change( p_aout, "equalizer", VLC_VAR_ADDCHOICE, &val, &text ); } var_AddCallback( p_aout, "equalizer", EqualizerCallback, NULL ); } } if( var_Type( p_aout, "audio-filter" ) == 0 ) { var_Create( p_aout, "audio-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); text.psz_string = _("Audio filters"); var_Change( p_aout, "audio-filter", VLC_VAR_SETTEXT, &text, NULL ); } if( var_Type( p_aout, "audio-visual" ) == 0 ) { var_Create( p_aout, "audio-visual", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); text.psz_string = _("Audio visualizations"); var_Change( p_aout, "audio-visual", VLC_VAR_SETTEXT, &text, NULL ); } var_Get( p_aout, "audio-filter", &val ); psz_filters = val.psz_string; var_Get( p_aout, "audio-visual", &val ); psz_visual = val.psz_string; /* parse user filter lists */ for( i_visual = 0; i_visual < 2; i_visual++ ) { char *psz_next = NULL; char *psz_parser = i_visual ? psz_visual : psz_filters; if( psz_parser == NULL || !*psz_parser ) continue; while( psz_parser && *psz_parser ) { aout_filter_t * p_filter = NULL; if( p_input->i_nb_filters >= AOUT_MAX_FILTERS ) { msg_Dbg( p_aout, "max filters reached (%d)", AOUT_MAX_FILTERS ); break; } while( *psz_parser == ' ' && *psz_parser == ':' ) { psz_parser++; } if( ( psz_next = strchr( psz_parser , ':' ) ) ) { *psz_next++ = '\0'; } if( *psz_parser =='\0' ) { break; } /* Create a VLC object */ p_filter = vlc_object_create( p_aout, sizeof(aout_filter_t) ); if( p_filter == NULL ) { msg_Err( p_aout, "cannot add user filter %s (skipped)", psz_parser ); psz_parser = psz_next; continue; } vlc_object_attach( p_filter , p_aout ); /* try to find the requested filter */ if( i_visual == 1 ) /* this can only be a visualization module */ { /* request format */ 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 ); } else /* this can be a audio filter module as well as a visualization module */ { /* request format */ memcpy( &p_filter->input, &chain_input_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, "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; } /* complete the filter chain if necessary */ if ( !AOUT_FMTS_IDENTICAL( &chain_input_format, &p_filter->input ) ) { 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; } } /* success */ p_filter->b_continuity = VLC_FALSE; p_input->pp_filters[p_input->i_nb_filters++] = p_filter; memcpy( &chain_input_format, &p_filter->output, sizeof( audio_sample_format_t ) ); /* next filter if any */ psz_parser = psz_next; } } if( psz_filters ) free( psz_filters ); if( psz_visual ) free( psz_visual ); /* complete the filter chain if necessary */ if ( !AOUT_FMTS_IDENTICAL( &chain_input_format, &chain_output_format ) ) { 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 { chain_output_format.i_rate = (__MAX(p_input->input.i_rate, p_aout->mixer.mixer.i_rate) * (100 + AOUT_MAX_RESAMPLING)) / 100; if ( chain_output_format.i_rate == p_aout->mixer.mixer.i_rate ) { /* Just in case... */ 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, &chain_output_format, &p_aout->mixer.mixer ) < 0 ) { 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; 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( p_input->input_alloc.i_bytes_per_sec, (int)(p_input->input.i_bytes_per_frame * p_input->input.i_rate / p_input->input.i_frame_length) ); /* Success */ p_input->b_error = VLC_FALSE; p_input->b_restart = VLC_FALSE; return 0; }