static void SetupOutputFormat( decoder_t *p_dec, bool b_trust ) { decoder_sys_t *p_sys = p_dec->p_sys; p_dec->fmt_out.i_codec = GetVlcAudioFormat( p_sys->p_context->sample_fmt ); p_dec->fmt_out.audio.i_format = p_dec->fmt_out.i_codec; p_dec->fmt_out.audio.i_rate = p_sys->p_context->sample_rate; /* */ if( p_sys->i_previous_channels == p_sys->p_context->channels && p_sys->i_previous_layout == p_sys->p_context->channel_layout ) return; if( b_trust ) { p_sys->i_previous_channels = p_sys->p_context->channels; p_sys->i_previous_layout = p_sys->p_context->channel_layout; } /* Specified order * FIXME should we use fmt_in.audio.i_physical_channels or not ? */ const unsigned i_order_max = 8 * sizeof(p_sys->p_context->channel_layout); uint32_t pi_order_src[i_order_max]; int i_channels_src = 0; if( p_sys->p_context->channel_layout ) { for( unsigned i = 0; i < sizeof(pi_channels_map)/sizeof(*pi_channels_map); i++ ) { if( p_sys->p_context->channel_layout & pi_channels_map[i][0] ) pi_order_src[i_channels_src++] = pi_channels_map[i][1]; } } else { /* Create default order */ if( b_trust ) msg_Warn( p_dec, "Physical channel configuration not set : guessing" ); for( unsigned int i = 0; i < __MIN( i_order_max, (unsigned)p_sys->p_context->channels ); i++ ) { if( i < sizeof(pi_channels_map)/sizeof(*pi_channels_map) ) pi_order_src[i_channels_src++] = pi_channels_map[i][1]; } } if( i_channels_src != p_sys->p_context->channels && b_trust ) msg_Err( p_dec, "Channel layout not understood" ); uint32_t i_layout_dst; int i_channels_dst; p_sys->b_extract = aout_CheckChannelExtraction( p_sys->pi_extraction, &i_layout_dst, &i_channels_dst, NULL, pi_order_src, i_channels_src ); if( i_channels_dst != i_channels_src && b_trust ) msg_Warn( p_dec, "%d channels are dropped", i_channels_src - i_channels_dst ); p_dec->fmt_out.audio.i_physical_channels = p_dec->fmt_out.audio.i_original_channels = i_layout_dst; aout_FormatPrepare( &p_dec->fmt_out.audio ); }
static int transcode_audio_initialize_encoder( sout_stream_id_t *id, sout_stream_t *p_stream ) { sout_stream_sys_t *p_sys = p_stream->p_sys; /* Initialization of encoder format structures */ es_format_Init( &id->p_encoder->fmt_in, id->p_decoder->fmt_in.i_cat, id->p_decoder->fmt_out.i_codec ); id->p_encoder->fmt_in.audio.i_format = id->p_decoder->fmt_out.i_codec; id->p_encoder->fmt_in.audio.i_rate = id->p_encoder->fmt_out.audio.i_rate; id->p_encoder->fmt_in.audio.i_physical_channels = id->p_encoder->fmt_out.audio.i_physical_channels; aout_FormatPrepare( &id->p_encoder->fmt_in.audio ); id->p_encoder->p_cfg = p_stream->p_sys->p_audio_cfg; id->p_encoder->p_module = module_need( id->p_encoder, "encoder", p_sys->psz_aenc, true ); if( !id->p_encoder->p_module ) { msg_Err( p_stream, "cannot find audio encoder (module:%s fourcc:%4.4s). Take a look few lines earlier to see possible reason.", p_sys->psz_aenc ? p_sys->psz_aenc : "any", (char *)&p_sys->i_acodec ); module_unneed( id->p_decoder, id->p_decoder->p_module ); id->p_decoder->p_module = NULL; return VLC_EGENERIC; } id->p_encoder->fmt_out.i_codec = vlc_fourcc_GetCodec( AUDIO_ES, id->p_encoder->fmt_out.i_codec ); /* Fix input format */ id->p_encoder->fmt_in.audio.i_format = id->p_encoder->fmt_in.i_codec; if( !id->p_encoder->fmt_in.audio.i_physical_channels || !id->p_encoder->fmt_in.audio.i_original_channels ) { if( id->p_encoder->fmt_in.audio.i_channels < 6 ) id->p_encoder->fmt_in.audio.i_physical_channels = id->p_encoder->fmt_in.audio.i_original_channels = pi_channels_maps[id->p_encoder->fmt_in.audio.i_channels]; } aout_FormatPrepare( &id->p_encoder->fmt_in.audio ); return VLC_SUCCESS; }
/***************************************************************************** * SplitConversion: split a conversion in two parts ***************************************************************************** * Returns the number of conversions required by the first part - 0 if only * one conversion was asked. * Beware : p_output_format can be modified during this function if the * developer passed SplitConversion( toto, titi, titi, ... ). That is legal. * SplitConversion( toto, titi, toto, ... ) isn't. *****************************************************************************/ static int SplitConversion( const audio_sample_format_t * p_input_format, const audio_sample_format_t * p_output_format, audio_sample_format_t * p_middle_format ) { vlc_bool_t b_format = (p_input_format->i_format != p_output_format->i_format); vlc_bool_t b_rate = (p_input_format->i_rate != p_output_format->i_rate); vlc_bool_t b_channels = (p_input_format->i_physical_channels != p_output_format->i_physical_channels) || (p_input_format->i_original_channels != p_output_format->i_original_channels); int i_nb_conversions = b_format + b_rate + b_channels; if ( i_nb_conversions <= 1 ) return 0; memcpy( p_middle_format, p_output_format, sizeof(audio_sample_format_t) ); if ( i_nb_conversions == 2 ) { if ( !b_format || !b_channels ) { p_middle_format->i_rate = p_input_format->i_rate; aout_FormatPrepare( p_middle_format ); return 1; } /* !b_rate */ p_middle_format->i_physical_channels = p_input_format->i_physical_channels; p_middle_format->i_original_channels = p_input_format->i_original_channels; aout_FormatPrepare( p_middle_format ); return 1; } /* i_nb_conversion == 3 */ p_middle_format->i_rate = p_input_format->i_rate; aout_FormatPrepare( p_middle_format ); return 2; }
/***************************************************************************** * Open: initialize as "audio filter" *****************************************************************************/ static int Open( vlc_object_t *p_this ) { filter_t *p_filter = (filter_t *)p_this; /* Allocate structure */ filter_sys_t *p_sys = p_filter->p_sys = malloc( sizeof(*p_sys) ); if( ! p_sys ) return VLC_ENOMEM; p_sys->scale = 1.0; p_sys->sample_rate = p_filter->fmt_in.audio.i_rate; p_sys->samples_per_frame = aout_FormatNbChannels( &p_filter->fmt_in.audio ); p_sys->bytes_per_sample = 4; p_sys->bytes_per_frame = p_sys->samples_per_frame * p_sys->bytes_per_sample; msg_Dbg( p_this, "format: %5i rate, %i nch, %i bps, %s", p_sys->sample_rate, p_sys->samples_per_frame, p_sys->bytes_per_sample, "fl32" ); p_sys->ms_stride = var_InheritInteger( p_this, "scaletempo-stride" ); p_sys->percent_overlap = var_InheritFloat( p_this, "scaletempo-overlap" ); p_sys->ms_search = var_InheritInteger( p_this, "scaletempo-search" ); msg_Dbg( p_this, "params: %i stride, %.3f overlap, %i search", p_sys->ms_stride, p_sys->percent_overlap, p_sys->ms_search ); p_sys->buf_queue = NULL; p_sys->buf_overlap = NULL; p_sys->table_blend = NULL; p_sys->buf_pre_corr = NULL; p_sys->table_window = NULL; p_sys->bytes_overlap = 0; p_sys->bytes_queued = 0; p_sys->bytes_to_slide = 0; p_sys->frames_stride_error = 0; if( reinit_buffers( p_filter ) != VLC_SUCCESS ) { Close( p_this ); return VLC_EGENERIC; } p_filter->fmt_in.audio.i_format = VLC_CODEC_FL32; aout_FormatPrepare(&p_filter->fmt_in.audio); p_filter->fmt_out.audio = p_filter->fmt_in.audio; p_filter->pf_audio_filter = DoWork; return VLC_SUCCESS; }
int transcode_audio_new( sout_stream_t *p_stream, sout_stream_id_t *id ) { sout_stream_sys_t *p_sys = p_stream->p_sys; audio_sample_format_t fmt_last; /* * Open decoder */ /* Initialization of decoder structures */ id->p_decoder->fmt_out = id->p_decoder->fmt_in; id->p_decoder->fmt_out.i_extra = 0; id->p_decoder->fmt_out.p_extra = 0; id->p_decoder->pf_decode_audio = NULL; id->p_decoder->pf_aout_format_update = audio_update_format; /* id->p_decoder->p_cfg = p_sys->p_audio_cfg; */ id->p_decoder->p_module = module_need( id->p_decoder, "decoder", "$codec", false ); if( !id->p_decoder->p_module ) { msg_Err( p_stream, "cannot find audio decoder" ); return VLC_EGENERIC; } /* decoders don't set audio.i_format, but audio filters use it */ id->p_decoder->fmt_out.audio.i_format = id->p_decoder->fmt_out.i_codec; aout_FormatPrepare( &id->p_decoder->fmt_out.audio ); fmt_last = id->p_decoder->fmt_out.audio; /* Fix AAC SBR changing number of channels and sampling rate */ if( !(id->p_decoder->fmt_in.i_codec == VLC_CODEC_MP4A && fmt_last.i_rate != id->p_encoder->fmt_in.audio.i_rate && fmt_last.i_channels != id->p_encoder->fmt_in.audio.i_channels) ) fmt_last.i_rate = id->p_decoder->fmt_in.audio.i_rate; /* * Open encoder */ if( transcode_audio_initialize_encoder( id, p_stream ) == VLC_EGENERIC ) return VLC_EGENERIC; if( unlikely( transcode_audio_initialize_filters( p_stream, id, p_sys, &fmt_last ) != VLC_SUCCESS ) ) return VLC_EGENERIC; return VLC_SUCCESS; }
static int UpdateAudioFormat( decoder_t *p_dec ) { int i_err; decoder_sys_t *p_sys = p_dec->p_sys; struct mpg123_frameinfo frame_info; /* Get details about the stream */ i_err = mpg123_info( p_sys->p_handle, &frame_info ); if( i_err != MPG123_OK ) { msg_Err( p_dec, "mpg123_info failed: %s", mpg123_plain_strerror( i_err ) ); return VLC_EGENERIC; } p_dec->fmt_out.i_bitrate = frame_info.bitrate * 1000; switch( frame_info.mode ) { case MPG123_M_DUAL: p_dec->fmt_out.audio.i_chan_mode = AOUT_CHANMODE_DUALMONO; /* fall through */ case MPG123_M_STEREO: case MPG123_M_JOINT: p_dec->fmt_out.audio.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; break; case MPG123_M_MONO: p_dec->fmt_out.audio.i_physical_channels = AOUT_CHAN_CENTER; break; default: return VLC_EGENERIC; } aout_FormatPrepare( &p_dec->fmt_out.audio ); /* Date management */ if( p_dec->fmt_out.audio.i_rate != frame_info.rate ) { p_dec->fmt_out.audio.i_rate = frame_info.rate; date_Init( &p_sys->end_date, p_dec->fmt_out.audio.i_rate, 1 ); date_Set( &p_sys->end_date, 0 ); } return decoder_UpdateAudioFormat( p_dec ); }
static filter_t *ResamplerCreate(filter_t *p_filter) { filter_t *p_resampler = vlc_object_create( p_filter, sizeof (filter_t) ); if( unlikely( p_resampler == NULL ) ) return NULL; p_resampler->owner.sys = NULL; p_resampler->p_cfg = NULL; p_resampler->fmt_in = p_filter->fmt_in; p_resampler->fmt_out = p_filter->fmt_in; p_resampler->fmt_out.audio.i_rate = vlc_atomic_load_float( &p_filter->p_sys->rate_shift ); aout_FormatPrepare( &p_resampler->fmt_out.audio ); p_resampler->p_module = module_need( p_resampler, "audio resampler", NULL, false ); if( p_resampler->p_module == NULL ) { msg_Err( p_filter, "Could not load resampler" ); vlc_object_release( p_resampler ); return NULL; } return p_resampler; }
/***************************************************************************** * 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; }
static int transcode_audio_filter_chain_build( sout_stream_t *p_stream, filter_chain_t *p_chain, const es_format_t *p_dst, const es_format_t *p_src ) { if( !transcode_audio_filter_needed( p_dst, p_src ) ) return VLC_SUCCESS; es_format_t current = *p_src; msg_Dbg( p_stream, "Looking for filter " "(%4.4s->%4.4s, channels %d->%d, rate %d->%d)", (const char *)&p_src->i_codec, (const char *)&p_dst->i_codec, p_src->audio.i_channels, p_dst->audio.i_channels, p_src->audio.i_rate, p_dst->audio.i_rate ); /* If any filter is needed, convert to fl32 */ if( current.i_codec != VLC_CODEC_FL32 ) { /* First step, convert to fl32 */ current.i_codec = current.audio.i_format = VLC_CODEC_FL32; aout_FormatPrepare( ¤t.audio ); if( !filter_chain_AppendFilter( p_chain, NULL, NULL, NULL, ¤t ) ) { msg_Err( p_stream, "Failed to find conversion filter to fl32" ); return VLC_EGENERIC; } current = *filter_chain_GetFmtOut( p_chain ); } /* Fix sample rate */ if( current.audio.i_rate != p_dst->audio.i_rate ) { current.audio.i_rate = p_dst->audio.i_rate; aout_FormatPrepare( ¤t.audio ); if( !filter_chain_AppendFilter( p_chain, NULL, NULL, NULL, ¤t ) ) { msg_Err( p_stream, "Failed to find conversion filter for resampling" ); return VLC_EGENERIC; } current = *filter_chain_GetFmtOut( p_chain ); } /* Fix channels */ if( current.audio.i_channels != p_dst->audio.i_channels ) { current.audio.i_channels = p_dst->audio.i_channels; current.audio.i_physical_channels = p_dst->audio.i_physical_channels; current.audio.i_original_channels = p_dst->audio.i_original_channels; if( ( !current.audio.i_physical_channels || !current.audio.i_original_channels ) && current.audio.i_channels < 6 ) current.audio.i_physical_channels = current.audio.i_original_channels = pi_channels_maps[current.audio.i_channels]; aout_FormatPrepare( ¤t.audio ); if( !filter_chain_AppendFilter( p_chain, NULL, NULL, NULL, ¤t ) ) { msg_Err( p_stream, "Failed to find conversion filter for channel mixing" ); return VLC_EGENERIC; } current = *filter_chain_GetFmtOut( p_chain ); } /* And last step, convert to the requested codec */ if( current.i_codec != p_dst->i_codec ) { current.i_codec = p_dst->i_codec; aout_FormatPrepare( ¤t.audio ); if( !filter_chain_AppendFilter( p_chain, NULL, NULL, NULL, ¤t ) ) { msg_Err( p_stream, "Failed to find conversion filter to %4.4s", (const char*)&p_dst->i_codec); return VLC_EGENERIC; } current = *filter_chain_GetFmtOut( p_chain ); } if( transcode_audio_filter_needed( p_dst, ¤t ) ) { /* Weird case, a filter has side effects, doomed */ msg_Err( p_stream, "Failed to create a valid audio filter chain" ); return VLC_EGENERIC; } msg_Dbg( p_stream, "Got complete audio filter chain" ); return VLC_SUCCESS; }
/***************************************************************************** * Open: open the audio device (the digital sound processor) ***************************************************************************** * This function opens the DSP as a usual non-blocking write-only file, and * modifies the p_aout->p_sys->i_fd with the file's descriptor. *****************************************************************************/ static int Open( vlc_object_t *p_this ) { aout_instance_t * p_aout = (aout_instance_t *)p_this; struct aout_sys_t * p_sys; char * psz_device; vlc_value_t val; /* Allocate structure */ p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) ); if( p_sys == NULL ) { msg_Err( p_aout, "out of memory" ); return VLC_ENOMEM; } /* Get device name */ if( (psz_device = config_GetPsz( p_aout, "dspdev" )) == NULL ) { msg_Err( p_aout, "no audio device specified (maybe /dev/dsp?)" ); free( p_sys ); return VLC_EGENERIC; } /* Open the sound device in non-blocking mode, because ALSA's OSS * emulation and some broken OSS drivers would make a blocking call * wait forever until the device is available. Since this breaks the * OSS spec, we immediately put it back to blocking mode if the * operation was successful. */ p_sys->i_fd = open( psz_device, O_WRONLY | O_NDELAY ); if( p_sys->i_fd < 0 ) { msg_Err( p_aout, "cannot open audio device (%s)", psz_device ); free( p_sys ); return VLC_EGENERIC; } /* if the opening was ok, put the device back in blocking mode */ fcntl( p_sys->i_fd, F_SETFL, fcntl( p_sys->i_fd, F_GETFL ) &~ FNDELAY ); free( psz_device ); p_aout->output.pf_play = Play; if ( var_Type( p_aout, "audio-device" ) == 0 ) { Probe( p_aout ); } if ( var_Get( p_aout, "audio-device", &val ) < 0 ) { /* Probe() has failed. */ free( p_sys ); return VLC_EGENERIC; } if ( val.i_int == AOUT_VAR_SPDIF ) { p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i'); } else if ( val.i_int == AOUT_VAR_5_1 ) { p_aout->output.output.i_format = AOUT_FMT_S16_NE; p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE; } else if ( val.i_int == AOUT_VAR_2F2R ) { p_aout->output.output.i_format = AOUT_FMT_S16_NE; p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; } else if ( val.i_int == AOUT_VAR_STEREO ) { p_aout->output.output.i_format = AOUT_FMT_S16_NE; p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; } else if ( val.i_int == AOUT_VAR_MONO ) { p_aout->output.output.i_format = AOUT_FMT_S16_NE; p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER; } else { /* This should not happen ! */ msg_Err( p_aout, "internal: can't find audio-device (%i)", val.i_int ); free( p_sys ); return VLC_EGENERIC; } val.b_bool = VLC_TRUE; var_Set( p_aout, "intf-change", val ); /* Reset the DSP device */ if( ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 ) { msg_Err( p_aout, "cannot reset OSS audio device" ); close( p_sys->i_fd ); free( p_sys ); return VLC_EGENERIC; } /* Set the output format */ if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) ) { int i_format = AFMT_AC3; if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 || i_format != AFMT_AC3 ) { msg_Err( p_aout, "cannot reset OSS audio device" ); close( p_sys->i_fd ); free( p_sys ); return VLC_EGENERIC; } p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i'); p_aout->output.i_nb_samples = A52_FRAME_NB; p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE; p_aout->output.output.i_frame_length = A52_FRAME_NB; aout_VolumeNoneInit( p_aout ); } if ( !AOUT_FMT_NON_LINEAR( &p_aout->output.output ) ) { unsigned int i_format = AFMT_S16_NE; unsigned int i_frame_size, i_fragments; unsigned int i_rate; unsigned int i_nb_channels; audio_buf_info audio_buf; if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 ) { msg_Err( p_aout, "cannot set audio output format" ); close( p_sys->i_fd ); free( p_sys ); return VLC_EGENERIC; } switch ( i_format ) { case AFMT_U8: p_aout->output.output.i_format = VLC_FOURCC('u','8',' ',' '); break; case AFMT_S8: p_aout->output.output.i_format = VLC_FOURCC('s','8',' ',' '); break; case AFMT_U16_LE: p_aout->output.output.i_format = VLC_FOURCC('u','1','6','l'); break; case AFMT_S16_LE: p_aout->output.output.i_format = VLC_FOURCC('s','1','6','l'); break; case AFMT_U16_BE: p_aout->output.output.i_format = VLC_FOURCC('u','1','6','b'); break; case AFMT_S16_BE: p_aout->output.output.i_format = VLC_FOURCC('s','1','6','b'); break; default: msg_Err( p_aout, "OSS fell back to an unknown format (%d)", i_format ); close( p_sys->i_fd ); free( p_sys ); return VLC_EGENERIC; } i_nb_channels = aout_FormatNbChannels( &p_aout->output.output ); /* Set the number of channels */ if( ioctl( p_sys->i_fd, SNDCTL_DSP_CHANNELS, &i_nb_channels ) < 0 || i_nb_channels != aout_FormatNbChannels( &p_aout->output.output ) ) { msg_Err( p_aout, "cannot set number of audio channels (%s)", aout_FormatPrintChannels( &p_aout->output.output) ); close( p_sys->i_fd ); free( p_sys ); return VLC_EGENERIC; } /* Set the output rate */ i_rate = p_aout->output.output.i_rate; if( ioctl( p_sys->i_fd, SNDCTL_DSP_SPEED, &i_rate ) < 0 ) { msg_Err( p_aout, "cannot set audio output rate (%i)", p_aout->output.output.i_rate ); close( p_sys->i_fd ); free( p_sys ); return VLC_EGENERIC; } if( i_rate != p_aout->output.output.i_rate ) { p_aout->output.output.i_rate = i_rate; } /* Set the fragment size */ aout_FormatPrepare( &p_aout->output.output ); /* i_fragment = xxxxyyyy where: xxxx is fragtotal * 1 << yyyy is fragsize */ i_fragments = 0; i_frame_size = FRAME_SIZE * p_aout->output.output.i_bytes_per_frame; while( i_frame_size >>= 1 ) { ++i_fragments; } i_fragments |= FRAME_COUNT << 16; if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFRAGMENT, &i_fragments ) < 0 ) { msg_Warn( p_aout, "cannot set fragment size (%.8x)", i_fragments ); } if( ioctl( p_sys->i_fd, SNDCTL_DSP_GETOSPACE, &audio_buf ) < 0 ) { msg_Err( p_aout, "cannot get fragment size" ); close( p_sys->i_fd ); free( p_sys ); return VLC_EGENERIC; } else { /* Number of fragments actually allocated */ p_aout->output.p_sys->i_fragstotal = audio_buf.fragstotal; /* Maximum duration the soundcard's buffer can hold */ p_aout->output.p_sys->max_buffer_duration = (mtime_t)audio_buf.fragstotal * audio_buf.fragsize * 1000000 / p_aout->output.output.i_bytes_per_frame / p_aout->output.output.i_rate * p_aout->output.output.i_frame_length; p_aout->output.i_nb_samples = audio_buf.fragsize / p_aout->output.output.i_bytes_per_frame; } aout_VolumeSoftInit( p_aout ); }
/***************************************************************************** * 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; }
static int Open(vlc_object_t *object) { filter_t *filter = (filter_t *)object; const es_format_t *src = &filter->fmt_in; es_format_t *dst = &filter->fmt_out; if (!AOUT_FMTS_SIMILAR(&src->audio, &dst->audio)) return VLC_EGENERIC; if (src->i_codec == dst->i_codec) return VLC_EGENERIC; cvt_direct_t direct = FindDirect(src->i_codec, dst->i_codec); if (direct) { filter->pf_audio_filter = direct; filter->p_sys = NULL; goto end; } /* */ filter_sys_t *sys = malloc(sizeof(*sys)); if (!sys) return VLC_ENOMEM; /* Find the cost minimal conversion */ for (unsigned mask = 0; mask <= 0x07; mask++) { memset(sys, 0, sizeof(*sys)); vlc_fourcc_t fsrc = src->i_codec; vlc_fourcc_t fdst = dst->i_codec; if (mask & 0x01) { sys->pre = FindSwap(&fsrc, fsrc); if (!sys->pre) continue; } if (mask & 0x02) { sys->post = FindSwap(&fdst, fdst); if (!sys->post) continue; } const bool has_middle = mask & 0x04; for (int i = 0; fsrc != fdst && i < 1 + has_middle; i++) { /* XXX Hardcoded middle format: native 16 bits */ vlc_fourcc_t ftarget = has_middle && i == 0 ? VLC_CODEC_S16N : fdst; sys->directs[i] = FindDirect(fsrc, ftarget); if (!sys->directs[i]) { sys->indirects[i] = FindIndirect(fsrc, ftarget); if (!sys->indirects[i]) break; sys->indirects_ratio[i][0] = aout_BitsPerSample(fsrc) / 8; sys->indirects_ratio[i][1] = aout_BitsPerSample(ftarget) / 8; } fsrc = ftarget; } if (fsrc != fdst) continue; /* We have a full conversion */ filter->pf_audio_filter = Filter; filter->p_sys = sys; goto end; } free(sys); return VLC_EGENERIC; end: dst->audio = src->audio; dst->audio.i_format = dst->i_codec; aout_FormatPrepare(&dst->audio); msg_Dbg(filter, "%4.4s->%4.4s, bits per sample: %i->%i", (char *)&src->i_codec, (char *)&dst->i_codec, src->audio.i_bitspersample, dst->audio.i_bitspersample); return VLC_SUCCESS; }
/***************************************************************************** * DecoderOpen: probe the decoder and return score *****************************************************************************/ static int DecoderOpen( vlc_object_t *p_this ) { decoder_t *p_dec = (decoder_t*)p_this; vlc_fourcc_t format = p_dec->fmt_in.i_codec; switch( p_dec->fmt_in.i_codec ) { case VLC_FOURCC('a','r','a','w'): case VLC_FOURCC('a','f','l','t'): /* _signed_ big endian samples (mov) */ case VLC_FOURCC('t','w','o','s'): /* _signed_ little endian samples (mov) */ case VLC_FOURCC('s','o','w','t'): format = vlc_fourcc_GetCodecAudio( p_dec->fmt_in.i_codec, p_dec->fmt_in.audio.i_bitspersample ); if( !format ) { msg_Err( p_dec, "bad parameters(bits/sample)" ); return VLC_EGENERIC; } break; } void (*decode) (void *, const uint8_t *, unsigned) = NULL; uint_fast8_t bits; switch( format ) { #ifdef WORDS_BIGENDIAN case VLC_CODEC_F64L: #else case VLC_CODEC_F64B: #endif format = VLC_CODEC_FL64; decode = F64IDecode; bits = 64; break; case VLC_CODEC_FL64: decode = F64NDecode; bits = 64; break; #ifdef WORDS_BIGENDIAN case VLC_CODEC_F32L: #else case VLC_CODEC_F32B: #endif format = VLC_CODEC_FL32; decode = F32IDecode; bits = 32; break; case VLC_CODEC_FL32: decode = F32NDecode; bits = 32; break; case VLC_CODEC_U32B: format = VLC_CODEC_S32N; decode = U32BDecode; bits = 32; break; case VLC_CODEC_U32L: format = VLC_CODEC_S32N; decode = U32LDecode; bits = 32; break; case VLC_CODEC_S32I: format = VLC_CODEC_S32N; decode = S32IDecode; /* fall through */ case VLC_CODEC_S32N: bits = 32; break; case VLC_CODEC_S24B32: format = VLC_CODEC_S32N; decode = S24B32Decode; bits = 32; break; case VLC_CODEC_S24L32: format = VLC_CODEC_S32N; decode = S24L32Decode; bits = 32; break; case VLC_CODEC_U24B: format = VLC_CODEC_S32N; decode = U24BDecode; bits = 24; break; case VLC_CODEC_U24L: format = VLC_CODEC_S32N; decode = U24LDecode; bits = 24; break; case VLC_CODEC_S24B: format = VLC_CODEC_S32N; decode = S24BDecode; bits = 24; break; case VLC_CODEC_S24L: format = VLC_CODEC_S32N; decode = S24LDecode; bits = 24; break; case VLC_CODEC_S20B: format = VLC_CODEC_S32N; decode = S20BDecode; bits = 20; break; case VLC_CODEC_U16B: format = VLC_CODEC_S16N; decode = U16BDecode; bits = 16; break; case VLC_CODEC_U16L: format = VLC_CODEC_S16N; decode = U16LDecode; bits = 16; break; case VLC_CODEC_S16I: format = VLC_CODEC_S16N; decode = S16IDecode; /* fall through */ case VLC_CODEC_S16N: bits = 16; break; case VLC_CODEC_DAT12: format = VLC_CODEC_S16N; decode = DAT12Decode; bits = 12; break; case VLC_CODEC_S8: decode = S8Decode; format = VLC_CODEC_U8; /* fall through */ case VLC_CODEC_U8: bits = 8; break; default: return VLC_EGENERIC; } if( p_dec->fmt_in.audio.i_channels == 0 || p_dec->fmt_in.audio.i_channels > INPUT_CHAN_MAX ) { msg_Err( p_dec, "bad channels count (1-%i): %i", AOUT_CHAN_MAX, p_dec->fmt_in.audio.i_channels ); return VLC_EGENERIC; } if( p_dec->fmt_in.audio.i_rate == 0 || p_dec->fmt_in.audio.i_rate > 384000 ) { msg_Err( p_dec, "bad samplerate: %d Hz", p_dec->fmt_in.audio.i_rate ); return VLC_EGENERIC; } msg_Dbg( p_dec, "samplerate:%dHz channels:%d bits/sample:%d", p_dec->fmt_in.audio.i_rate, p_dec->fmt_in.audio.i_channels, p_dec->fmt_in.audio.i_bitspersample ); /* Allocate the memory needed to store the decoder's structure */ decoder_sys_t *p_sys = malloc(sizeof(*p_sys)); if( unlikely(p_sys == NULL) ) return VLC_ENOMEM; /* Set output properties */ p_dec->fmt_out.i_codec = format; p_dec->fmt_out.audio.channel_type = p_dec->fmt_in.audio.channel_type; p_dec->fmt_out.audio.i_format = format; p_dec->fmt_out.audio.i_rate = p_dec->fmt_in.audio.i_rate; if( p_dec->fmt_in.audio.i_channels <= ARRAY_SIZE( pi_channels_maps ) - 1 ) { if( p_dec->fmt_in.audio.i_physical_channels ) p_dec->fmt_out.audio.i_physical_channels = p_dec->fmt_in.audio.i_physical_channels; else p_dec->fmt_out.audio.i_physical_channels = pi_channels_maps[p_dec->fmt_in.audio.i_channels]; } else { /* Unknown channel map, let the aout/filters decide what to do */ p_dec->fmt_out.audio.i_channels = p_dec->fmt_in.audio.i_channels; p_dec->fmt_out.audio.i_physical_channels = 0; } aout_FormatPrepare( &p_dec->fmt_out.audio ); p_sys->decode = decode; p_sys->framebits = bits * p_dec->fmt_out.audio.i_channels; assert( p_sys->framebits ); date_Init( &p_sys->end_date, p_dec->fmt_out.audio.i_rate, 1 ); date_Set( &p_sys->end_date, 0 ); p_dec->pf_decode = DecodeBlock; p_dec->pf_flush = Flush; p_dec->p_sys = p_sys; return VLC_SUCCESS; }
/***************************************************************************** * aout_DecNew : create a decoder *****************************************************************************/ static aout_input_t * DecNew( vlc_object_t * p_this, aout_instance_t * p_aout, audio_sample_format_t * p_format ) { aout_input_t * p_input; input_thread_t * p_input_thread; vlc_value_t val; /* We can only be called by the decoder, so no need to lock * p_input->lock. */ vlc_mutex_lock( &p_aout->mixer_lock ); if ( p_aout->i_nb_inputs >= AOUT_MAX_INPUTS ) { msg_Err( p_aout, "too many inputs already (%d)", p_aout->i_nb_inputs ); return NULL; } p_input = malloc(sizeof(aout_input_t)); if ( p_input == NULL ) { msg_Err( p_aout, "out of memory" ); return NULL; } vlc_mutex_init( p_aout, &p_input->lock ); p_input->b_changed = 0; p_input->b_error = 1; aout_FormatPrepare( p_format ); memcpy( &p_input->input, p_format, sizeof(audio_sample_format_t) ); p_aout->pp_inputs[p_aout->i_nb_inputs] = p_input; p_aout->i_nb_inputs++; if ( p_aout->mixer.b_error ) { int i; var_Destroy( p_aout, "audio-device" ); var_Destroy( p_aout, "audio-channels" ); /* Recreate the output using the new format. */ if ( aout_OutputNew( p_aout, p_format ) < 0 ) { for ( i = 0; i < p_aout->i_nb_inputs - 1; i++ ) { vlc_mutex_lock( &p_aout->pp_inputs[i]->lock ); aout_InputDelete( p_aout, p_aout->pp_inputs[i] ); vlc_mutex_unlock( &p_aout->pp_inputs[i]->lock ); } vlc_mutex_unlock( &p_aout->mixer_lock ); return p_input; } /* Create other input streams. */ for ( i = 0; i < p_aout->i_nb_inputs - 1; i++ ) { vlc_mutex_lock( &p_aout->pp_inputs[i]->lock ); aout_InputDelete( p_aout, p_aout->pp_inputs[i] ); aout_InputNew( p_aout, p_aout->pp_inputs[i] ); vlc_mutex_unlock( &p_aout->pp_inputs[i]->lock ); } } else { aout_MixerDelete( p_aout ); } if ( aout_MixerNew( p_aout ) == -1 ) { aout_OutputDelete( p_aout ); vlc_mutex_unlock( &p_aout->mixer_lock ); return NULL; } aout_InputNew( p_aout, p_input ); vlc_mutex_unlock( &p_aout->mixer_lock ); var_Create( p_this, "audio-desync", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); var_Get( p_this, "audio-desync", &val ); p_input->i_desync = val.i_int * 1000; p_input_thread = (input_thread_t *)vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_PARENT ); if( p_input_thread ) { p_input->i_pts_delay = p_input_thread->i_pts_delay; p_input->i_pts_delay += p_input->i_desync; vlc_object_release( p_input_thread ); } else { p_input->i_pts_delay = DEFAULT_PTS_DELAY; p_input->i_pts_delay += p_input->i_desync; } return p_input; }
static int audio_update_format( decoder_t *p_dec ) { aout_FormatPrepare( &p_dec->fmt_out.audio ); return 0; }
/***************************************************************************** * Open: open the audio device (the digital sound processor) ***************************************************************************** * This function opens the DSP as a usual non-blocking write-only file, and * modifies the p_aout->p_sys->i_fd with the file's descriptor. *****************************************************************************/ static int Open( vlc_object_t *p_this ) { audio_output_t * p_aout = (audio_output_t *)p_this; struct aout_sys_t * p_sys; char * psz_device; vlc_value_t val; /* Allocate structure */ p_aout->sys = p_sys = malloc( sizeof( aout_sys_t ) ); if( p_sys == NULL ) return VLC_ENOMEM; /* Get device name */ if( (psz_device = var_InheritString( p_aout, "oss-audio-device" )) == NULL ) { msg_Err( p_aout, "no audio device specified (maybe /dev/dsp?)" ); free( p_sys ); return VLC_EGENERIC; } /* Open the sound device in non-blocking mode, because ALSA's OSS * emulation and some broken OSS drivers would make a blocking call * wait forever until the device is available. Since this breaks the * OSS spec, we immediately put it back to blocking mode if the * operation was successful. */ p_sys->i_fd = vlc_open( psz_device, O_WRONLY | O_NDELAY ); if( p_sys->i_fd < 0 ) { msg_Err( p_aout, "cannot open audio device (%s)", psz_device ); free( psz_device ); free( p_sys ); return VLC_EGENERIC; } /* if the opening was ok, put the device back in blocking mode */ fcntl( p_sys->i_fd, F_SETFL, fcntl( p_sys->i_fd, F_GETFL ) &~ FNDELAY ); free( psz_device ); p_aout->pf_play = aout_PacketPlay; p_aout->pf_pause = aout_PacketPause; p_aout->pf_flush = aout_PacketFlush; if ( var_Type( p_aout, "audio-device" ) == 0 ) Probe( p_aout ); var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL ); if ( var_Get( p_aout, "audio-device", &val ) < 0 ) /* Probe() has failed. */ goto error; if ( val.i_int == AOUT_VAR_SPDIF ) { p_aout->format.i_format = VLC_CODEC_SPDIFL; } else if ( val.i_int == AOUT_VAR_5_1 ) { p_aout->format.i_format = VLC_CODEC_S16N; p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE; } else if ( val.i_int == AOUT_VAR_2F2R ) { p_aout->format.i_format = VLC_CODEC_S16N; p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; } else if ( val.i_int == AOUT_VAR_STEREO ) { p_aout->format.i_format = VLC_CODEC_S16N; p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; } else if ( val.i_int == AOUT_VAR_MONO ) { p_aout->format.i_format = VLC_CODEC_S16N; p_aout->format.i_physical_channels = AOUT_CHAN_CENTER; } else { /* This should not happen ! */ msg_Err( p_aout, "internal: can't find audio-device (%"PRId64")", val.i_int ); goto error; } var_TriggerCallback( p_aout, "intf-change" ); /* Reset the DSP device */ if( ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 ) { msg_Err( p_aout, "cannot reset OSS audio device" ); goto error; } /* Set the output format */ if ( AOUT_FMT_SPDIF( &p_aout->format ) ) { int i_format = AFMT_AC3; if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 || i_format != AFMT_AC3 ) { msg_Err( p_aout, "cannot reset OSS audio device" ); goto error; } p_aout->format.i_format = VLC_CODEC_SPDIFL; p_aout->format.i_bytes_per_frame = AOUT_SPDIF_SIZE; p_aout->format.i_frame_length = A52_FRAME_NB; aout_PacketInit( p_aout, &p_sys->packet, A52_FRAME_NB ); aout_VolumeNoneInit( p_aout ); } else { unsigned int i_format = AFMT_S16_NE; unsigned int i_frame_size, i_fragments; unsigned int i_rate; unsigned int i_nb_channels; audio_buf_info audio_buf; if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 ) { msg_Err( p_aout, "cannot set audio output format" ); goto error; } switch ( i_format ) { case AFMT_U8: p_aout->format.i_format = VLC_CODEC_U8; break; case AFMT_S8: p_aout->format.i_format = VLC_CODEC_S8; break; case AFMT_U16_LE: p_aout->format.i_format = VLC_CODEC_U16L; break; case AFMT_S16_LE: p_aout->format.i_format = VLC_CODEC_S16L; break; case AFMT_U16_BE: p_aout->format.i_format = VLC_CODEC_U16B; break; case AFMT_S16_BE: p_aout->format.i_format = VLC_CODEC_S16B; break; default: msg_Err( p_aout, "OSS fell back to an unknown format (%d)", i_format ); goto error; } i_nb_channels = aout_FormatNbChannels( &p_aout->format ); /* Set the number of channels */ if( ioctl( p_sys->i_fd, SNDCTL_DSP_CHANNELS, &i_nb_channels ) < 0 || i_nb_channels != aout_FormatNbChannels( &p_aout->format ) ) { msg_Err( p_aout, "cannot set number of audio channels (%s)", aout_FormatPrintChannels( &p_aout->format) ); goto error; } /* Set the output rate */ i_rate = p_aout->format.i_rate; if( ioctl( p_sys->i_fd, SNDCTL_DSP_SPEED, &i_rate ) < 0 ) { msg_Err( p_aout, "cannot set audio output rate (%i)", p_aout->format.i_rate ); goto error; } if( i_rate != p_aout->format.i_rate ) { p_aout->format.i_rate = i_rate; } /* Set the fragment size */ aout_FormatPrepare( &p_aout->format ); /* i_fragment = xxxxyyyy where: xxxx is fragtotal * 1 << yyyy is fragsize */ i_frame_size = ((uint64_t)p_aout->format.i_bytes_per_frame * p_aout->format.i_rate * 65536) / (48000 * 2 * 2) / FRAME_COUNT; i_fragments = 4; while( i_fragments < 12 && (1U << i_fragments) < i_frame_size ) { ++i_fragments; } i_fragments |= FRAME_COUNT << 16; if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFRAGMENT, &i_fragments ) < 0 ) { msg_Warn( p_aout, "cannot set fragment size (%.8x)", i_fragments ); } if( ioctl( p_sys->i_fd, SNDCTL_DSP_GETOSPACE, &audio_buf ) < 0 ) { msg_Err( p_aout, "cannot get fragment size" ); goto error; } /* Number of fragments actually allocated */ p_aout->sys->i_fragstotal = audio_buf.fragstotal; /* Maximum duration the soundcard's buffer can hold */ p_aout->sys->max_buffer_duration = (mtime_t)audio_buf.fragstotal * audio_buf.fragsize * 1000000 / p_aout->format.i_bytes_per_frame / p_aout->format.i_rate * p_aout->format.i_frame_length; aout_PacketInit( p_aout, &p_sys->packet, audio_buf.fragsize/p_aout->format.i_bytes_per_frame ); aout_VolumeSoftInit( p_aout ); } /* Create OSS thread and wait for its readiness. */ if( vlc_clone( &p_sys->thread, OSSThread, p_aout, VLC_THREAD_PRIORITY_OUTPUT ) ) { msg_Err( p_aout, "cannot create OSS thread (%m)" ); aout_PacketDestroy( p_aout ); goto error; } return VLC_SUCCESS; error: var_DelCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL ); close( p_sys->i_fd ); free( p_sys ); return VLC_EGENERIC; }
/***************************************************************************** * Open: open the audio device ***************************************************************************** * This function opens and setups Win32 waveOut *****************************************************************************/ static int Open( vlc_object_t *p_this ) { aout_instance_t *p_aout = (aout_instance_t *)p_this; vlc_value_t val; int i; /* Allocate structure */ p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) ); if( p_aout->output.p_sys == NULL ) { msg_Err( p_aout, "out of memory" ); return VLC_EGENERIC; } p_aout->output.pf_play = Play; p_aout->b_die = VLC_FALSE; if( var_Type( p_aout, "audio-device" ) == 0 ) { Probe( p_aout ); } if( var_Get( p_aout, "audio-device", &val ) < 0 ) { /* Probe() has failed. */ free( p_aout->output.p_sys ); return VLC_EGENERIC; } var_Create( p_aout, "waveout-float32", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); /* Open the device */ if( val.i_int == AOUT_VAR_SPDIF ) { p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i'); if( OpenWaveOut( p_aout, VLC_FOURCC('s','p','d','i'), p_aout->output.output.i_physical_channels, aout_FormatNbChannels( &p_aout->output.output ), p_aout->output.output.i_rate, VLC_FALSE ) != VLC_SUCCESS ) { msg_Err( p_aout, "cannot open waveout audio device" ); free( p_aout->output.p_sys ); return VLC_EGENERIC; } /* Calculate the frame size in bytes */ p_aout->output.i_nb_samples = A52_FRAME_NB; p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE; p_aout->output.output.i_frame_length = A52_FRAME_NB; p_aout->output.p_sys->i_buffer_size = p_aout->output.output.i_bytes_per_frame; aout_VolumeNoneInit( p_aout ); } else { if( val.i_int == AOUT_VAR_5_1 ) { p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE; } else if( val.i_int == AOUT_VAR_2F2R ) { p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; } else if( val.i_int == AOUT_VAR_MONO ) { p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER; } else { p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; } if( OpenWaveOutPCM( p_aout, &p_aout->output.output.i_format, p_aout->output.output.i_physical_channels, aout_FormatNbChannels( &p_aout->output.output ), p_aout->output.output.i_rate, VLC_FALSE ) != VLC_SUCCESS ) { msg_Err( p_aout, "cannot open waveout audio device" ); free( p_aout->output.p_sys ); return VLC_EGENERIC; } /* Calculate the frame size in bytes */ p_aout->output.i_nb_samples = FRAME_SIZE; aout_FormatPrepare( &p_aout->output.output ); p_aout->output.p_sys->i_buffer_size = FRAME_SIZE * p_aout->output.output.i_bytes_per_frame; aout_VolumeSoftInit( p_aout ); } waveOutReset( p_aout->output.p_sys->h_waveout ); /* Allocate silence buffer */ p_aout->output.p_sys->p_silence_buffer = malloc( p_aout->output.p_sys->i_buffer_size ); if( p_aout->output.p_sys->p_silence_buffer == NULL ) { free( p_aout->output.p_sys ); msg_Err( p_aout, "out of memory" ); return 1; } /* Zero the buffer. WinCE doesn't have calloc(). */ memset( p_aout->output.p_sys->p_silence_buffer, 0, p_aout->output.p_sys->i_buffer_size ); /* Now we need to setup our waveOut play notification structure */ p_aout->output.p_sys->p_notif = vlc_object_create( p_aout, sizeof(notification_thread_t) ); p_aout->output.p_sys->p_notif->p_aout = p_aout; p_aout->output.p_sys->event = CreateEvent( NULL, FALSE, FALSE, NULL ); /* Then launch the notification thread */ if( vlc_thread_create( p_aout->output.p_sys->p_notif, "waveOut Notification Thread", WaveOutThread, VLC_THREAD_PRIORITY_HIGHEST, VLC_FALSE ) ) { msg_Err( p_aout, "cannot create WaveOutThread" ); } /* We need to kick off the playback in order to have the callback properly * working */ for( i = 0; i < FRAMES_NUM; i++ ) { p_aout->output.p_sys->waveheader[i].dwFlags = WHDR_DONE; p_aout->output.p_sys->waveheader[i].dwUser = 0; } PlayWaveOut( p_aout, p_aout->output.p_sys->h_waveout, &p_aout->output.p_sys->waveheader[0], NULL ); 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; }
static int OpenBinauralizer(vlc_object_t *p_this) { filter_t *p_filter = (filter_t *)p_this; audio_format_t *infmt = &p_filter->fmt_in.audio; audio_format_t *outfmt = &p_filter->fmt_out.audio; filter_sys_t *p_sys; p_sys = p_filter->p_sys = (filter_sys_t*)new(std::nothrow)filter_sys_t(); if (p_sys == NULL) return VLC_ENOMEM; p_sys->mode = filter_sys_t::BINAURALIZER; p_sys->i_rate = p_filter->fmt_in.audio.i_rate; p_sys->i_inputNb = p_filter->fmt_in.audio.i_channels; p_sys->i_outputNb = 2; if (allocateBuffers(p_sys) != VLC_SUCCESS) { delete p_sys; return VLC_ENOMEM; } unsigned s = 0; p_sys->speakers = new CAmbisonicSpeaker[infmt->i_channels](); p_sys->speakers[s++].SetPosition({DegreesToRadians(30), 0.f, 1.f}); p_sys->speakers[s++].SetPosition({DegreesToRadians(-30), 0.f, 1.f}); if ((infmt->i_physical_channels & AOUT_CHANS_MIDDLE) == AOUT_CHANS_MIDDLE) { /* Middle */ p_sys->speakers[s++].SetPosition({DegreesToRadians(110), 0.f, 1.f}); p_sys->speakers[s++].SetPosition({DegreesToRadians(-110), 0.f, 1.f}); } if ((infmt->i_physical_channels & AOUT_CHANS_REAR) == AOUT_CHANS_REAR) { /* Rear */ p_sys->speakers[s++].SetPosition({DegreesToRadians(145), 0.f, 1.f}); p_sys->speakers[s++].SetPosition({DegreesToRadians(-145), 0.f, 1.f}); } if ((infmt->i_physical_channels & AOUT_CHAN_CENTER) == AOUT_CHAN_CENTER) p_sys->speakers[s++].SetPosition({DegreesToRadians(0), 0.f, 1.f}); if ((infmt->i_physical_channels & AOUT_CHAN_LFE) == AOUT_CHAN_LFE) p_sys->speakers[s++].SetPosition({DegreesToRadians(0), 0.f, 0.5f}); std::string HRTFPath = getHRTFPath(p_filter); msg_Dbg(p_filter, "Using the HRTF file: %s", HRTFPath.c_str()); unsigned i_tailLength = 0; if (!p_sys->binauralizer.Configure(p_sys->i_rate, AMB_BLOCK_TIME_LEN, p_sys->speakers, infmt->i_channels, i_tailLength, HRTFPath)) { msg_Err(p_filter, "Error creating the binauralizer."); delete p_sys; return VLC_EGENERIC; } p_sys->binauralizer.Reset(); outfmt->i_format = infmt->i_format = VLC_CODEC_FL32; outfmt->i_physical_channels = AOUT_CHANS_STEREO; aout_FormatPrepare(infmt); aout_FormatPrepare(outfmt); p_filter->pf_audio_filter = Mix; p_filter->pf_flush = Flush; p_filter->pf_change_viewpoint = ChangeViewpoint; return VLC_SUCCESS; }
/***************************************************************************** * Open: open the audio device *****************************************************************************/ static int Start ( audio_output_t *p_aout, audio_sample_format_t *fmt ) { aout_sys_t *p_sys = p_aout->sys; char *psz_mode; ULONG i_kai_mode; KAISPEC ks_wanted, ks_obtained; int i_nb_channels; int i_bytes_per_frame; vlc_value_t val, text; audio_sample_format_t format = *fmt; if( var_Get( p_aout, "audio-device", &val ) != VLC_ENOVAR ) { /* The user has selected an audio device. */ if ( val.i_int == AOUT_VAR_STEREO ) { format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; } else if ( val.i_int == AOUT_VAR_MONO ) { format.i_physical_channels = AOUT_CHAN_CENTER; } } psz_mode = var_InheritString( p_aout, "kai-audio-device" ); if( !psz_mode ) psz_mode = ( char * )ppsz_kai_audio_device[ 0 ]; // "auto" i_kai_mode = KAIM_AUTO; if( strcmp( psz_mode, "dart" ) == 0 ) i_kai_mode = KAIM_DART; else if( strcmp( psz_mode, "uniaud" ) == 0 ) i_kai_mode = KAIM_UNIAUD; msg_Dbg( p_aout, "selected mode = %s", psz_mode ); if( psz_mode != ppsz_kai_audio_device[ 0 ]) free( psz_mode ); i_nb_channels = aout_FormatNbChannels( &format ); if ( i_nb_channels > 2 ) { /* KAI doesn't support more than two channels. */ i_nb_channels = 2; format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; } /* Support s16l only */ format.i_format = VLC_CODEC_S16L; aout_FormatPrepare( &format ); i_bytes_per_frame = format.i_bytes_per_frame; /* Initialize library */ if( kaiInit( i_kai_mode )) { msg_Err( p_aout, "cannot initialize KAI"); return VLC_EGENERIC; } ks_wanted.usDeviceIndex = 0; ks_wanted.ulType = KAIT_PLAY; ks_wanted.ulBitsPerSample = BPS_16; ks_wanted.ulSamplingRate = format.i_rate; ks_wanted.ulDataFormat = MCI_WAVE_FORMAT_PCM; ks_wanted.ulChannels = i_nb_channels; ks_wanted.ulNumBuffers = 2; ks_wanted.ulBufferSize = FRAME_SIZE * i_bytes_per_frame; ks_wanted.fShareable = !var_InheritBool( p_aout, "kai-audio-exclusive-mode"); ks_wanted.pfnCallBack = KaiCallback; ks_wanted.pCallBackData = p_aout; msg_Dbg( p_aout, "requested ulBufferSize = %ld", ks_wanted.ulBufferSize ); /* Open the sound device. */ if( kaiOpen( &ks_wanted, &ks_obtained, &p_sys->hkai )) { msg_Err( p_aout, "cannot open KAI device"); goto exit_kai_done; } msg_Dbg( p_aout, "open in %s mode", ks_obtained.fShareable ? "shareable" : "exclusive" ); msg_Dbg( p_aout, "obtained i_nb_samples = %lu", ks_obtained.ulBufferSize / i_bytes_per_frame ); msg_Dbg( p_aout, "obtained i_bytes_per_frame = %d", format.i_bytes_per_frame ); p_sys->format = *fmt = format; p_aout->time_get = aout_PacketTimeGet; p_aout->play = Play; p_aout->pause = NULL; p_aout->flush = aout_PacketFlush; aout_SoftVolumeStart( p_aout ); aout_PacketInit( p_aout, &p_sys->packet, ks_obtained.ulBufferSize / i_bytes_per_frame, &format ); if ( var_Type( p_aout, "audio-device" ) == 0 ) { /* First launch. */ var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE ); text.psz_string = _("Audio Device"); var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL ); val.i_int = AOUT_VAR_STEREO; text.psz_string = _("Stereo"); var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text ); val.i_int = AOUT_VAR_MONO; text.psz_string = _("Mono"); var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text ); if ( i_nb_channels == 2 ) { val.i_int = AOUT_VAR_STEREO; } else { val.i_int = AOUT_VAR_MONO; } var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL ); var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL ); } /* Prevent SIG_FPE */ _control87(MCW_EM, MCW_EM); return VLC_SUCCESS; exit_kai_done : kaiDone(); return VLC_EGENERIC; }
void *codec_init (demux_t *demux, es_format_t *fmt) { if (fmt->i_cat == AUDIO_ES) aout_FormatPrepare (&fmt->audio); return es_out_Add (demux->out, fmt); }
/***************************************************************************** * Open: open the audio device *****************************************************************************/ static int Start ( audio_output_t *p_aout, audio_sample_format_t *fmt ) { aout_sys_t *p_sys = p_aout->sys; char *psz_mode; ULONG i_kai_mode; KAISPEC ks_wanted, ks_obtained; int i_nb_channels; int i_bytes_per_frame; vlc_value_t val, text; audio_sample_format_t format = *fmt; psz_mode = var_InheritString( p_aout, "kai-audio-device" ); if( !psz_mode ) psz_mode = ( char * )ppsz_kai_audio_device[ 0 ]; // "auto" i_kai_mode = KAIM_AUTO; if( strcmp( psz_mode, "dart" ) == 0 ) i_kai_mode = KAIM_DART; else if( strcmp( psz_mode, "uniaud" ) == 0 ) i_kai_mode = KAIM_UNIAUD; msg_Dbg( p_aout, "selected mode = %s", psz_mode ); if( psz_mode != ppsz_kai_audio_device[ 0 ]) free( psz_mode ); i_nb_channels = aout_FormatNbChannels( &format ); if ( i_nb_channels >= 2 ) { /* KAI doesn't support more than two channels. */ i_nb_channels = 2; format.i_physical_channels = AOUT_CHANS_STEREO; } else format.i_physical_channels = AOUT_CHAN_CENTER; /* Support S16 only */ format.i_format = VLC_CODEC_S16N; aout_FormatPrepare( &format ); i_bytes_per_frame = format.i_bytes_per_frame; /* Initialize library */ if( kaiInit( i_kai_mode )) { msg_Err( p_aout, "cannot initialize KAI"); return VLC_EGENERIC; } ks_wanted.usDeviceIndex = 0; ks_wanted.ulType = KAIT_PLAY; ks_wanted.ulBitsPerSample = BPS_16; ks_wanted.ulSamplingRate = format.i_rate; ks_wanted.ulDataFormat = MCI_WAVE_FORMAT_PCM; ks_wanted.ulChannels = i_nb_channels; ks_wanted.ulNumBuffers = 2; ks_wanted.ulBufferSize = FRAME_SIZE * i_bytes_per_frame; ks_wanted.fShareable = !var_InheritBool( p_aout, "kai-audio-exclusive-mode"); ks_wanted.pfnCallBack = KaiCallback; ks_wanted.pCallBackData = p_aout; msg_Dbg( p_aout, "requested ulBufferSize = %ld", ks_wanted.ulBufferSize ); /* Open the sound device. */ if( kaiOpen( &ks_wanted, &ks_obtained, &p_sys->hkai )) { msg_Err( p_aout, "cannot open KAI device"); goto exit_kai_done; } msg_Dbg( p_aout, "open in %s mode", ks_obtained.fShareable ? "shareable" : "exclusive" ); msg_Dbg( p_aout, "obtained i_nb_samples = %lu", ks_obtained.ulBufferSize / i_bytes_per_frame ); msg_Dbg( p_aout, "obtained i_bytes_per_frame = %d", format.i_bytes_per_frame ); p_sys->format = *fmt = format; p_aout->time_get = TimeGet; p_aout->play = Play; p_aout->pause = Pause; p_aout->flush = Flush; aout_SoftVolumeStart( p_aout ); CreateBuffer( p_aout, AUDIO_BUFFER_SIZE_IN_SECONDS * format.i_rate * format.i_bytes_per_frame ); /* Prevent SIG_FPE */ _control87(MCW_EM, MCW_EM); return VLC_SUCCESS; exit_kai_done : kaiDone(); return VLC_EGENERIC; }
int transcode_audio_process( sout_stream_t *p_stream, sout_stream_id_t *id, block_t *in, block_t **out ) { sout_stream_sys_t *p_sys = p_stream->p_sys; block_t *p_block, *p_audio_buf; *out = NULL; if( unlikely( in == NULL ) ) { block_t *p_block; do { p_block = id->p_encoder->pf_encode_audio(id->p_encoder, NULL ); block_ChainAppend( out, p_block ); } while( p_block ); return VLC_SUCCESS; } while( (p_audio_buf = id->p_decoder->pf_decode_audio( id->p_decoder, &in )) ) { if( p_sys->b_master_sync ) { mtime_t i_pts = date_Get( &id->interpolated_pts ) + 1; mtime_t i_drift = 0; if( likely( p_audio_buf->i_pts != VLC_TS_INVALID ) ) i_drift = p_audio_buf->i_pts - i_pts; if ( unlikely(i_drift > MASTER_SYNC_MAX_DRIFT || i_drift < -MASTER_SYNC_MAX_DRIFT) ) { msg_Dbg( p_stream, "audio drift is too high (%"PRId64"), resetting master sync", i_drift ); date_Set( &id->interpolated_pts, p_audio_buf->i_pts ); i_pts = p_audio_buf->i_pts + 1; } if( likely(p_audio_buf->i_pts != VLC_TS_INVALID ) ) p_sys->i_master_drift = p_audio_buf->i_pts - i_pts; date_Increment( &id->interpolated_pts, p_audio_buf->i_nb_samples ); p_audio_buf->i_pts = i_pts; } p_audio_buf->i_dts = p_audio_buf->i_pts; /* Check if audio format has changed, and filters need reinit */ if( unlikely( ( id->p_decoder->fmt_out.audio.i_rate != p_sys->fmt_audio.i_rate ) || ( id->p_decoder->fmt_out.audio.i_physical_channels != p_sys->fmt_audio.i_physical_channels ) ) ) { msg_Info( p_stream, "Audio changed, trying to reinitialize filters" ); if( id->p_af_chain != NULL ) aout_FiltersDelete( (vlc_object_t *)NULL, id->p_af_chain ); /* decoders don't set audio.i_format, but audio filters use it */ id->p_decoder->fmt_out.audio.i_format = id->p_decoder->fmt_out.i_codec; aout_FormatPrepare( &id->p_decoder->fmt_out.audio ); if( transcode_audio_initialize_filters( p_stream, id, p_sys, &id->p_decoder->fmt_out.audio ) != VLC_SUCCESS ) return VLC_EGENERIC; } /* Run filter chain */ p_audio_buf = aout_FiltersPlay( id->p_af_chain, p_audio_buf, INPUT_RATE_DEFAULT ); if( !p_audio_buf ) abort(); p_audio_buf->i_dts = p_audio_buf->i_pts; p_block = id->p_encoder->pf_encode_audio( id->p_encoder, p_audio_buf ); block_ChainAppend( out, p_block ); block_Release( p_audio_buf ); } return VLC_SUCCESS; }
/***************************************************************************** * OpenFilter: *****************************************************************************/ static int OpenFilter( vlc_object_t *p_this ) { filter_t *p_filter = (filter_t *)p_this; filter_sys_t *p_sys; audio_format_t *audio_in = &p_filter->fmt_in.audio; audio_format_t *audio_out = &p_filter->fmt_out.audio; if( ( audio_in->i_format != audio_out->i_format ) || ( audio_in->i_rate != audio_out->i_rate ) ) return VLC_EGENERIC; /* Allocate the memory needed to store the module's structure */ p_sys = p_filter->p_sys = malloc( sizeof(filter_sys_t) ); if( unlikely( p_sys == NULL ) ) return VLC_ENOMEM; /* get number of and layout of input channels */ uint32_t i_output_physical = 0; uint8_t pi_map_ch[ AOUT_CHAN_MAX ] = { 0 }; /* which out channel each in channel is mapped to */ p_sys->b_normalize = var_InheritBool( p_this, REMAP_CFG "normalize" ); for( uint8_t in_ch = 0, wg4_i = 0; in_ch < audio_in->i_channels; in_ch++, wg4_i++ ) { /* explode in_channels in the right order */ while( ( audio_in->i_physical_channels & pi_vlc_chan_order_wg4[ wg4_i ] ) == 0 ) { wg4_i++; assert( wg4_i < sizeof( pi_vlc_chan_order_wg4 )/sizeof( pi_vlc_chan_order_wg4[0] ) ); } unsigned channel_wg4idx_len = sizeof( channel_wg4idx )/sizeof( channel_wg4idx[0] ); uint8_t *pi_chnidx = memchr( channel_wg4idx, wg4_i, channel_wg4idx_len ); assert( pi_chnidx != NULL ); uint8_t chnidx = pi_chnidx - channel_wg4idx; uint8_t out_idx = var_InheritInteger( p_this, channel_name[chnidx] ); pi_map_ch[in_ch] = channel_wg4idx[ out_idx ]; i_output_physical |= channel_flag[ out_idx ]; } i_output_physical = CanonicaliseChannels( i_output_physical ); audio_out->i_physical_channels = i_output_physical; aout_FormatPrepare( audio_out ); /* condense out_channels */ uint8_t out_ch_sorted[ AOUT_CHAN_MAX ]; for( uint8_t i = 0, wg4_i = 0; i < audio_out->i_channels; i++, wg4_i++ ) { while( ( audio_out->i_physical_channels & pi_vlc_chan_order_wg4[ wg4_i ] ) == 0 ) { wg4_i++; assert( wg4_i < sizeof( pi_vlc_chan_order_wg4 )/sizeof( pi_vlc_chan_order_wg4[0] ) ); } out_ch_sorted[ i ] = wg4_i; } bool b_multiple = false; /* whether we need to add channels (multiple in mapped to an out) */ memset( p_sys->nb_in_ch, 0, sizeof( p_sys->nb_in_ch ) ); for( uint8_t i = 0; i < audio_in->i_channels; i++ ) { uint8_t wg4_out_ch = pi_map_ch[i]; uint8_t *pi_out_ch = memchr( out_ch_sorted, wg4_out_ch, audio_out->i_channels ); assert( pi_out_ch != NULL ); p_sys->map_ch[i] = pi_out_ch - out_ch_sorted; if( ++p_sys->nb_in_ch[ p_sys->map_ch[i] ] > 1 ) b_multiple = true; } msg_Dbg( p_filter, "%s '%4.4s'->'%4.4s' %d Hz->%d Hz %s->%s", "Remap filter", (char *)&audio_in->i_format, (char *)&audio_out->i_format, audio_in->i_rate, audio_out->i_rate, aout_FormatPrintChannels( audio_in ), aout_FormatPrintChannels( audio_out ) ); p_sys->pf_remap = GetRemapFun( audio_in, b_multiple ); if( !p_sys->pf_remap ) { msg_Err( p_filter, "Could not decide on %s remap function", b_multiple ? "an add" : "a copy" ); free( p_sys ); return VLC_EGENERIC; } p_filter->pf_audio_filter = Remap; return VLC_SUCCESS; }
int transcode_audio_new( sout_stream_t *p_stream, sout_stream_id_t *id ) { sout_stream_sys_t *p_sys = p_stream->p_sys; audio_sample_format_t fmt_last; /* * Open decoder */ /* Initialization of decoder structures */ id->p_decoder->fmt_out = id->p_decoder->fmt_in; id->p_decoder->fmt_out.i_extra = 0; id->p_decoder->fmt_out.p_extra = 0; id->p_decoder->pf_decode_audio = NULL; id->p_decoder->pf_aout_format_update = audio_update_format; /* id->p_decoder->p_cfg = p_sys->p_audio_cfg; */ id->p_decoder->p_module = module_need( id->p_decoder, "decoder", "$codec", false ); if( !id->p_decoder->p_module ) { msg_Err( p_stream, "cannot find audio decoder" ); return VLC_EGENERIC; } /* decoders don't set audio.i_format, but audio filters use it */ id->p_decoder->fmt_out.audio.i_format = id->p_decoder->fmt_out.i_codec; aout_FormatPrepare( &id->p_decoder->fmt_out.audio ); fmt_last = id->p_decoder->fmt_out.audio; /* Fix AAC SBR changing number of channels and sampling rate */ if( !(id->p_decoder->fmt_in.i_codec == VLC_CODEC_MP4A && fmt_last.i_rate != id->p_encoder->fmt_in.audio.i_rate && fmt_last.i_channels != id->p_encoder->fmt_in.audio.i_channels) ) fmt_last.i_rate = id->p_decoder->fmt_in.audio.i_rate; /* * Open encoder */ /* Initialization of encoder format structures */ es_format_Init( &id->p_encoder->fmt_in, id->p_decoder->fmt_in.i_cat, id->p_decoder->fmt_out.i_codec ); id->p_encoder->fmt_in.audio.i_format = id->p_decoder->fmt_out.i_codec; id->p_encoder->fmt_in.audio.i_rate = id->p_encoder->fmt_out.audio.i_rate; id->p_encoder->fmt_in.audio.i_physical_channels = id->p_encoder->fmt_out.audio.i_physical_channels; aout_FormatPrepare( &id->p_encoder->fmt_in.audio ); id->p_encoder->p_cfg = p_stream->p_sys->p_audio_cfg; id->p_encoder->p_module = module_need( id->p_encoder, "encoder", p_sys->psz_aenc, true ); if( !id->p_encoder->p_module ) { msg_Err( p_stream, "cannot find audio encoder (module:%s fourcc:%4.4s). Take a look few lines earlier to see possible reason.", p_sys->psz_aenc ? p_sys->psz_aenc : "any", (char *)&p_sys->i_acodec ); module_unneed( id->p_decoder, id->p_decoder->p_module ); id->p_decoder->p_module = NULL; return VLC_EGENERIC; } id->p_encoder->fmt_out.i_codec = vlc_fourcc_GetCodec( AUDIO_ES, id->p_encoder->fmt_out.i_codec ); /* Fix input format */ id->p_encoder->fmt_in.audio.i_format = id->p_encoder->fmt_in.i_codec; if( !id->p_encoder->fmt_in.audio.i_physical_channels || !id->p_encoder->fmt_in.audio.i_original_channels ) { if( id->p_encoder->fmt_in.audio.i_channels < 6 ) id->p_encoder->fmt_in.audio.i_physical_channels = id->p_encoder->fmt_in.audio.i_original_channels = pi_channels_maps[id->p_encoder->fmt_in.audio.i_channels]; } aout_FormatPrepare( &id->p_encoder->fmt_in.audio ); if( unlikely( transcode_audio_initialize_filters( p_stream, id, p_sys, &fmt_last ) != VLC_SUCCESS ) ) return VLC_EGENERIC; return VLC_SUCCESS; }
static int Open( vlc_object_t *p_this ) { decoder_t *p_dec = (decoder_t *)p_this; decoder_sys_t *p_sys; if( p_dec->fmt_in.i_codec != VLC_CODEC_DTS || p_dec->fmt_in.audio.i_rate == 0 || p_dec->fmt_in.audio.i_physical_channels == 0 || p_dec->fmt_in.audio.i_original_channels == 0 || p_dec->fmt_in.audio.i_bytes_per_frame == 0 || p_dec->fmt_in.audio.i_frame_length == 0 ) return VLC_EGENERIC; /* Allocate the memory needed to store the module's structure */ p_sys = p_dec->p_sys = malloc( sizeof(decoder_sys_t) ); if( p_sys == NULL ) return VLC_ENOMEM; p_sys->b_dynrng = var_InheritBool( p_this, "dts-dynrng" ); p_sys->b_dontwarn = 0; /* We'll do our own downmixing, thanks. */ p_sys->i_nb_channels = aout_FormatNbChannels( &p_dec->fmt_in.audio ); if( channels_vlc2dca( &p_dec->fmt_in.audio, &p_sys->i_flags ) != VLC_SUCCESS ) { msg_Warn( p_this, "unknown sample format!" ); free( p_sys ); return VLC_EGENERIC; } //p_sys->i_flags |= DCA_ADJUST_LEVEL; /* Initialize libdca */ p_sys->p_libdca = dca_init( 0 ); if( p_sys->p_libdca == NULL ) { msg_Err( p_this, "unable to initialize libdca" ); free( p_sys ); return VLC_EGENERIC; } /* libdca channel order * libdca currently only decodes 5.1, even if you have a DTS-ES source. */ static const uint32_t pi_channels_in[] = { AOUT_CHAN_CENTER, AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_REARCENTER, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, AOUT_CHAN_LFE, 0 }; aout_CheckChannelReorder( pi_channels_in, NULL, p_dec->fmt_in.audio.i_physical_channels, p_sys->pi_chan_table ); p_dec->fmt_out.i_cat = AUDIO_ES; p_dec->fmt_out.audio = p_dec->fmt_in.audio; p_dec->fmt_out.audio.i_format = VLC_CODEC_FL32; p_dec->fmt_out.i_codec = p_dec->fmt_out.audio.i_format; aout_FormatPrepare( &p_dec->fmt_out.audio ); if( decoder_UpdateAudioFormat( p_dec ) ) { es_format_Init( &p_dec->fmt_out, UNKNOWN_ES, 0 ); Close( p_this ); return VLC_EGENERIC; } p_dec->pf_decode = Decode; p_dec->pf_flush = NULL; return VLC_SUCCESS; }
static int Audio_GetOutput(decoder_t *p_dec, picture_t **pp_out_pic, block_t **pp_out_block, bool *p_abort, mtime_t i_timeout) { decoder_sys_t *p_sys = p_dec->p_sys; mc_api_out out; int i_ret; (void) p_abort; assert(!pp_out_pic && pp_out_block); i_ret = p_sys->api->get_out(p_sys->api, &out, i_timeout); if (i_ret != 1) return i_ret; if (out.type == MC_OUT_TYPE_BUF) { block_t *p_block = NULL; if (!p_sys->b_has_format) { msg_Warn(p_dec, "Buffers returned before output format is set, dropping frame"); return p_sys->api->release_out(p_sys->api, out.u.buf.i_index, false); } p_block = block_Alloc(out.u.buf.i_size); if (!p_block) return -1; p_block->i_nb_samples = out.u.buf.i_size / p_dec->fmt_out.audio.i_bytes_per_frame; if (p_sys->u.audio.b_extract) { aout_ChannelExtract(p_block->p_buffer, p_dec->fmt_out.audio.i_channels, out.u.buf.p_ptr, p_sys->u.audio.i_channels, p_block->i_nb_samples, p_sys->u.audio.pi_extraction, p_dec->fmt_out.audio.i_bitspersample); } else memcpy(p_block->p_buffer, out.u.buf.p_ptr, out.u.buf.i_size); if (out.u.buf.i_ts != 0 && out.u.buf.i_ts != date_Get(&p_sys->u.audio.i_end_date)) date_Set(&p_sys->u.audio.i_end_date, out.u.buf.i_ts); p_block->i_pts = date_Get(&p_sys->u.audio.i_end_date); p_block->i_length = date_Increment(&p_sys->u.audio.i_end_date, p_block->i_nb_samples) - p_block->i_pts; if (p_sys->api->release_out(p_sys->api, out.u.buf.i_index, false)) { block_Release(p_block); return -1; } *pp_out_block = p_block; return 1; } else { uint32_t i_layout_dst; int i_channels_dst; assert(out.type == MC_OUT_TYPE_CONF); if (out.u.conf.audio.channel_count <= 0 || out.u.conf.audio.channel_count > 8 || out.u.conf.audio.sample_rate <= 0) { msg_Warn( p_dec, "invalid audio properties channels count %d, sample rate %d", out.u.conf.audio.channel_count, out.u.conf.audio.sample_rate); return -1; } msg_Err(p_dec, "output: channel_count: %d, channel_mask: 0x%X, rate: %d", out.u.conf.audio.channel_count, out.u.conf.audio.channel_mask, out.u.conf.audio.sample_rate); p_dec->fmt_out.i_codec = VLC_CODEC_S16N; p_dec->fmt_out.audio.i_format = p_dec->fmt_out.i_codec; p_dec->fmt_out.audio.i_rate = out.u.conf.audio.sample_rate; date_Init(&p_sys->u.audio.i_end_date, out.u.conf.audio.sample_rate, 1 ); p_sys->u.audio.i_channels = out.u.conf.audio.channel_count; p_sys->u.audio.b_extract = aout_CheckChannelExtraction(p_sys->u.audio.pi_extraction, &i_layout_dst, &i_channels_dst, NULL, pi_audio_order_src, p_sys->u.audio.i_channels); if (p_sys->u.audio.b_extract) msg_Warn(p_dec, "need channel extraction: %d -> %d", p_sys->u.audio.i_channels, i_channels_dst); p_dec->fmt_out.audio.i_original_channels = p_dec->fmt_out.audio.i_physical_channels = i_layout_dst; aout_FormatPrepare(&p_dec->fmt_out.audio); if (decoder_UpdateAudioFormat(p_dec)) return -1; p_sys->b_has_format = true; return 0; } }
static int PAOpenStream( audio_output_t *p_aout ) { aout_sys_t *p_sys = p_aout->sys; const PaHostErrorInfo* paLastHostErrorInfo = Pa_GetLastHostErrorInfo(); PaStreamParameters paStreamParameters; vlc_value_t val; int i_channels, i_err; uint32_t i_channel_mask; if( var_Get( p_aout, "audio-device", &val ) < 0 ) { return VLC_EGENERIC; } if( val.i_int == AOUT_VAR_5_1 ) { p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE; } else if( val.i_int == AOUT_VAR_3F2R ) { p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; } else if( val.i_int == AOUT_VAR_2F2R ) { p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; } else if( val.i_int == AOUT_VAR_MONO ) { p_aout->format.i_physical_channels = AOUT_CHAN_CENTER; } else { p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; } i_channels = aout_FormatNbChannels( &p_aout->format ); msg_Dbg( p_aout, "nb_channels requested = %d", i_channels ); i_channel_mask = p_aout->format.i_physical_channels; /* Calculate the frame size in bytes */ p_sys->i_sample_size = 4 * i_channels; aout_FormatPrepare( &p_aout->format ); aout_PacketInit( p_aout, &p_sys->packet, FRAME_SIZE ); aout_VolumeSoftInit( p_aout ); /* Check for channel reordering */ p_aout->sys->i_channel_mask = i_channel_mask; p_aout->sys->i_bits_per_sample = 32; /* forced to paFloat32 */ p_aout->sys->i_channels = i_channels; p_aout->sys->b_chan_reorder = aout_CheckChannelReorder( NULL, pi_channels_out, i_channel_mask, i_channels, p_aout->sys->pi_chan_table ); if( p_aout->sys->b_chan_reorder ) { msg_Dbg( p_aout, "channel reordering needed" ); } paStreamParameters.device = p_sys->i_device_id; paStreamParameters.channelCount = i_channels; paStreamParameters.sampleFormat = paFloat32; paStreamParameters.suggestedLatency = p_sys->deviceInfo->defaultLowOutputLatency; paStreamParameters.hostApiSpecificStreamInfo = NULL; i_err = Pa_OpenStream( &p_sys->p_stream, NULL /* no input */, &paStreamParameters, (double)p_aout->format.i_rate, FRAME_SIZE, paClipOff, paCallback, p_sys ); if( i_err != paNoError ) { msg_Err( p_aout, "Pa_OpenStream returns %d : %s", i_err, Pa_GetErrorText( i_err ) ); if( i_err == paUnanticipatedHostError ) { msg_Err( p_aout, "type %d code %ld : %s", paLastHostErrorInfo->hostApiType, paLastHostErrorInfo->errorCode, paLastHostErrorInfo->errorText ); } p_sys->p_stream = 0; aout_PacketDestroy( p_aout ); return VLC_EGENERIC; } i_err = Pa_StartStream( p_sys->p_stream ); if( i_err != paNoError ) { msg_Err( p_aout, "Pa_StartStream() failed" ); Pa_CloseStream( p_sys->p_stream ); aout_PacketDestroy( p_aout ); return VLC_EGENERIC; } return VLC_SUCCESS; }
static int Open (vlc_object_t *obj) { demux_t *demux = (demux_t *)obj; demux_sys_t *sys = vlc_obj_malloc(obj, sizeof (*sys)); if (unlikely(sys == NULL)) return VLC_ENOMEM; /* Open the device */ const char *device = demux->psz_location; if (device == NULL || !device[0]) device = "default"; const int mode = SND_PCM_NONBLOCK /*| SND_PCM_NO_AUTO_RESAMPLE*/ | SND_PCM_NO_AUTO_CHANNELS /*| SND_PCM_NO_AUTO_FORMAT*/; snd_pcm_t *pcm; int val = snd_pcm_open (&pcm, device, SND_PCM_STREAM_CAPTURE, mode); if (val != 0) { msg_Err (demux, "cannot open ALSA device \"%s\": %s", device, snd_strerror (val)); return VLC_EGENERIC; } sys->pcm = pcm; msg_Dbg (demux, "using ALSA device: %s", device); DumpDevice (VLC_OBJECT(demux), pcm); /* Negotiate capture parameters */ snd_pcm_hw_params_t *hw; es_format_t fmt; unsigned param; int dir; snd_pcm_hw_params_alloca (&hw); snd_pcm_hw_params_any (pcm, hw); Dump (demux, "initial hardware setup:\n", snd_pcm_hw_params_dump, hw); val = snd_pcm_hw_params_set_rate_resample (pcm, hw, 0); if (val) { msg_Err (demux, "cannot disable resampling: %s", snd_strerror (val)); goto error; } val = snd_pcm_hw_params_set_access (pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED); if (val) { msg_Err (demux, "cannot set access mode: %s", snd_strerror (val)); goto error; } snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN; for (size_t i = 0; i < sizeof (choices) / sizeof (choices[0]); i++) if (snd_pcm_hw_params_test_format (pcm, hw, choices[i]) == 0) { val = snd_pcm_hw_params_set_format (pcm, hw, choices[i]); if (val) { msg_Err (demux, "cannot set sample format: %s", snd_strerror (val)); goto error; } format = choices[i]; break; } if (format == SND_PCM_FORMAT_UNKNOWN) { msg_Err (demux, "no supported sample format"); goto error; } assert ((size_t)format < (sizeof (formats) / sizeof (formats[0]))); es_format_Init (&fmt, AUDIO_ES, formats[format]); fmt.audio.i_format = fmt.i_codec; param = 1 + var_InheritBool (demux, "alsa-stereo"); val = snd_pcm_hw_params_set_channels_max (pcm, hw, ¶m); if (val) { msg_Err (demux, "cannot restrict channels count: %s", snd_strerror (val)); goto error; } val = snd_pcm_hw_params_set_channels_last (pcm, hw, ¶m); if (val) { msg_Err (demux, "cannot set channels count: %s", snd_strerror (val)); goto error; } assert (param > 0); assert (param < (sizeof (channel_maps) / sizeof (channel_maps[0]))); fmt.audio.i_channels = param; fmt.audio.i_physical_channels = channel_maps[param - 1]; param = var_InheritInteger (demux, "alsa-samplerate"); val = snd_pcm_hw_params_set_rate_max (pcm, hw, ¶m, NULL); if (val) { msg_Err (demux, "cannot restrict rate to %u Hz or less: %s", 192000, snd_strerror (val)); goto error; } val = snd_pcm_hw_params_set_rate_last (pcm, hw, ¶m, &dir); if (val) { msg_Err (demux, "cannot set sample rate: %s", snd_strerror (val)); goto error; } if (dir) msg_Warn (demux, "sample rate is not integral"); fmt.audio.i_rate = param; sys->rate = param; sys->start = mdate (); sys->caching = INT64_C(1000) * var_InheritInteger (demux, "live-caching"); param = sys->caching; val = snd_pcm_hw_params_set_buffer_time_near (pcm, hw, ¶m, NULL); if (val) { msg_Err (demux, "cannot set buffer duration: %s", snd_strerror (val)); goto error; } param /= 4; val = snd_pcm_hw_params_set_period_time_near (pcm, hw, ¶m, NULL); if (val) { msg_Err (demux, "cannot set period: %s", snd_strerror (val)); goto error; } val = snd_pcm_hw_params_get_period_size (hw, &sys->period_size, &dir); if (val) { msg_Err (demux, "cannot get period size: %s", snd_strerror (val)); goto error; } if (dir > 0) sys->period_size++; /* Commit hardware parameters */ val = snd_pcm_hw_params (pcm, hw); if (val) { msg_Err (demux, "cannot commit hardware parameters: %s", snd_strerror (val)); goto error; } Dump (demux, "final HW setup:\n", snd_pcm_hw_params_dump, hw); /* Kick recording */ aout_FormatPrepare (&fmt.audio); sys->es = es_out_Add (demux->out, &fmt); demux->p_sys = sys; if (vlc_clone (&sys->thread, Thread, demux, VLC_THREAD_PRIORITY_INPUT)) { es_out_Del (demux->out, sys->es); goto error; } demux->pf_demux = NULL; demux->pf_control = Control; return VLC_SUCCESS; error: snd_pcm_close (pcm); return VLC_EGENERIC; }
/***************************************************************************** * 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; }