Commit 43c4b5aa authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

Factorize aout filter pipeline

parent 6400a004
......@@ -103,7 +103,8 @@ void aout_InputCheckAndRestart( aout_instance_t * p_aout, aout_input_t * p_input
bool aout_InputIsEmpty( aout_instance_t * p_aout, aout_input_t * p_input );
/* From filters.c : */
int aout_FiltersCreatePipeline ( aout_instance_t * p_aout, filter_t ** pp_filters, int * pi_nb_filters, const audio_sample_format_t * p_input_format, const audio_sample_format_t * p_output_format );
int aout_FiltersCreatePipeline( aout_instance_t *, filter_t **, int *,
const audio_sample_format_t *, const audio_sample_format_t * );
void aout_FiltersDestroyPipeline( filter_t *const *, unsigned );
void aout_FiltersPlay( filter_t *const *, unsigned, aout_buffer_t ** );
......
......@@ -67,6 +67,7 @@ static filter_t * FindFilter( aout_instance_t * p_aout,
sizeof(audio_sample_format_t) );
p_filter->fmt_out.i_codec = p_output_format->i_format;
p_filter->pf_audio_buffer_new = aout_FilterBufferNew;
p_filter->p_owner = NULL;
p_filter->p_module = module_need( p_filter, "audio filter", NULL, false );
if ( p_filter->p_module == NULL )
......@@ -79,198 +80,102 @@ static filter_t * FindFilter( aout_instance_t * p_aout,
return p_filter;
}
/*****************************************************************************
* 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 )
/**
* Splits audio format conversion in two simpler conversions
* @return 0 on successful split, -1 if the input and output formats are too
* similar to split the conversion.
*/
static int SplitConversion( const audio_sample_format_t *restrict infmt,
const audio_sample_format_t *restrict outfmt,
audio_sample_format_t *midfmt )
{
bool b_format =
(p_input_format->i_format != p_output_format->i_format);
bool b_rate = (p_input_format->i_rate != p_output_format->i_rate);
bool 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) );
*midfmt = *outfmt;
if ( i_nb_conversions == 2 )
if( infmt->i_rate != outfmt->i_rate )
midfmt->i_rate = infmt->i_rate;
else
if( infmt->i_physical_channels != outfmt->i_physical_channels
|| infmt->i_original_channels != outfmt->i_original_channels )
{
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;
midfmt->i_physical_channels = infmt->i_physical_channels;
midfmt->i_original_channels = infmt->i_original_channels;
}
else
return -1;
/* i_nb_conversion == 3 */
p_middle_format->i_rate = p_input_format->i_rate;
aout_FormatPrepare( p_middle_format );
return 2;
}
static void ReleaseFilter( filter_t * p_filter )
{
module_unneed( p_filter, p_filter->p_module );
vlc_object_release( p_filter );
aout_FormatPrepare( midfmt );
return AOUT_FMTS_IDENTICAL( infmt, midfmt ) ? -1 : 0;
}
/*****************************************************************************
* aout_FiltersCreatePipeline: create a filters pipeline to transform a sample
* format to another
*****************************************************************************
* pi_nb_filters must be initialized before calling this function
*****************************************************************************/
int aout_FiltersCreatePipeline( aout_instance_t * p_aout,
filter_t ** pp_filters_start,
int * pi_nb_filters,
const audio_sample_format_t * p_input_format,
const audio_sample_format_t * p_output_format )
/**
* Allocates audio format conversion filters
* @param obj parent VLC object for new filters
* @param filters table of filters [IN/OUT]
* @param nb_filters pointer to the number of filters in the table [IN/OUT]
* @param infmt input audio format
* @param outfmt output audio format
* @return 0 on success, -1 on failure
*/
int aout_FiltersCreatePipeline( aout_instance_t *obj,
filter_t **filters,
int *nb_filters,
const audio_sample_format_t *restrict infmt,
const audio_sample_format_t *restrict outfmt )
{
filter_t** pp_filters = pp_filters_start + *pi_nb_filters;
audio_sample_format_t temp_format;
int i_nb_conversions;
if ( AOUT_FMTS_IDENTICAL( p_input_format, p_output_format ) )
{
msg_Dbg( p_aout, "no need for any filter" );
return 0;
}
audio_sample_format_t curfmt = *outfmt;
unsigned i = 0, max = *nb_filters - AOUT_MAX_FILTERS;
aout_FormatsPrint( p_aout, "filter(s)", p_input_format, p_output_format );
filters += *nb_filters;
aout_FormatsPrint( obj, "filter(s)", infmt, outfmt );
if( *pi_nb_filters + 1 > AOUT_MAX_FILTERS )
while( !AOUT_FMTS_IDENTICAL( infmt, &curfmt ) )
{
msg_Err( p_aout, "max filter reached (%d)", AOUT_MAX_FILTERS );
dialog_Fatal( p_aout, _("Audio filtering failed"),
_("The maximum number of filters (%d) was reached."),
AOUT_MAX_FILTERS );
return -1;
}
if( i >= max )
{
msg_Err( obj, "max (%u) filters reached", AOUT_MAX_FILTERS );
dialog_Fatal( obj, _("Audio filtering failed"),
_("The maximum number of filters (%u) was reached."),
AOUT_MAX_FILTERS );
goto rollback;
}
/* Try to find a filter to do the whole conversion. */
pp_filters[0] = FindFilter( p_aout, p_input_format, p_output_format );
if ( pp_filters[0] != NULL )
{
msg_Dbg( p_aout, "found a filter for the whole conversion" );
++*pi_nb_filters;
return 0;
}
/* Make room and prepend a filter */
memmove( filters + 1, filters, i * sizeof( *filters ) );
/* We'll have to split the conversion. We always do the downmixing
* before the resampling, because the audio decoder can probably do it
* for us. */
i_nb_conversions = SplitConversion( p_input_format,
p_output_format, &temp_format );
if ( !i_nb_conversions )
{
/* There was only one conversion to do, and we already failed. */
msg_Err( p_aout, "couldn't find a filter for the conversion "
"%4.4s -> %4.4s",
(const char *)&p_input_format->i_format,
(const char *)&p_output_format->i_format );
return -1;
}
pp_filters[0] = FindFilter( p_aout, p_input_format, &temp_format );
if ( pp_filters[0] == NULL && i_nb_conversions == 2 )
{
/* Try with only one conversion. */
SplitConversion( p_input_format, &temp_format, &temp_format );
pp_filters[0] = FindFilter( p_aout, p_input_format, &temp_format );
}
if ( pp_filters[0] == NULL )
{
msg_Err( p_aout,
"couldn't find a filter for the first part of the conversion" );
return -1;
}
/* We have the first stage of the conversion. Find a filter for
* the rest. */
if( *pi_nb_filters + 2 > AOUT_MAX_FILTERS )
{
ReleaseFilter( pp_filters[0] );
msg_Err( p_aout, "max filter reached (%d)", AOUT_MAX_FILTERS );
dialog_Fatal( p_aout, _("Audio filtering failed"),
_("The maximum number of filters (%d) was reached."),
AOUT_MAX_FILTERS );
return -1;
}
pp_filters[1] = FindFilter( p_aout, &pp_filters[0]->fmt_out.audio,
p_output_format );
if ( pp_filters[1] == NULL )
{
/* Try to split the conversion. */
i_nb_conversions = SplitConversion( &pp_filters[0]->fmt_out.audio,
p_output_format, &temp_format );
if ( !i_nb_conversions )
*filters = FindFilter( obj, infmt, &curfmt );
if( *filters != NULL )
{
ReleaseFilter( pp_filters[0] );
msg_Err( p_aout,
"couldn't find a filter for the second part of the conversion" );
return -1;
i++;
break; /* done! */
}
if( *pi_nb_filters + 3 > AOUT_MAX_FILTERS )
audio_sample_format_t midfmt;
/* Split the conversion */
if( SplitConversion( infmt, &curfmt, &midfmt ) )
{
ReleaseFilter( pp_filters[0] );
msg_Err( p_aout, "max filter reached (%d)", AOUT_MAX_FILTERS );
dialog_Fatal( p_aout, _("Audio filtering failed"),
_("The maximum number of filters (%d) was reached."),
AOUT_MAX_FILTERS );
return -1;
msg_Err( obj, "conversion pipeline failed: %4.4s -> %4.4s",
(const char *)&infmt->i_format,
(const char *)&outfmt->i_format );
goto rollback;
}
pp_filters[1] = FindFilter( p_aout, &pp_filters[0]->fmt_out.audio,
&temp_format );
pp_filters[2] = FindFilter( p_aout, &temp_format,
p_output_format );
if ( pp_filters[1] == NULL || pp_filters[2] == NULL )
*filters = FindFilter( obj, &midfmt, &curfmt );
if( *filters == NULL )
{
ReleaseFilter( pp_filters[0] );
if ( pp_filters[1] != NULL )
{
ReleaseFilter( pp_filters[1] );
}
if ( pp_filters[2] != NULL )
{
ReleaseFilter( pp_filters[2] );
}
msg_Err( p_aout,
"couldn't find filters for the second part of the conversion" );
return -1;
msg_Err( obj, "cannot find filter for simple conversion" );
goto rollback;
}
*pi_nb_filters += 3;
msg_Dbg( p_aout, "found 3 filters for the whole conversion" );
}
else
{
*pi_nb_filters += 2;
msg_Dbg( p_aout, "found 2 filters for the whole conversion" );
curfmt = midfmt;
i++;
}
msg_Dbg( obj, "conversion pipeline completed" );
*nb_filters += i;
return 0;
rollback:
aout_FiltersDestroyPipeline( filters, i );
return -1;
}
/**
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment