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 ...@@ -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 ); bool aout_InputIsEmpty( aout_instance_t * p_aout, aout_input_t * p_input );
/* From filters.c : */ /* 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_FiltersDestroyPipeline( filter_t *const *, unsigned );
void aout_FiltersPlay( filter_t *const *, unsigned, aout_buffer_t ** ); void aout_FiltersPlay( filter_t *const *, unsigned, aout_buffer_t ** );
......
...@@ -67,6 +67,7 @@ static filter_t * FindFilter( aout_instance_t * p_aout, ...@@ -67,6 +67,7 @@ static filter_t * FindFilter( aout_instance_t * p_aout,
sizeof(audio_sample_format_t) ); sizeof(audio_sample_format_t) );
p_filter->fmt_out.i_codec = p_output_format->i_format; p_filter->fmt_out.i_codec = p_output_format->i_format;
p_filter->pf_audio_buffer_new = aout_FilterBufferNew; 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 ); p_filter->p_module = module_need( p_filter, "audio filter", NULL, false );
if ( p_filter->p_module == NULL ) if ( p_filter->p_module == NULL )
...@@ -79,198 +80,102 @@ static filter_t * FindFilter( aout_instance_t * p_aout, ...@@ -79,198 +80,102 @@ static filter_t * FindFilter( aout_instance_t * p_aout,
return p_filter; return p_filter;
} }
/***************************************************************************** /**
* SplitConversion: split a conversion in two parts * Splits audio format conversion in two simpler conversions
***************************************************************************** * @return 0 on successful split, -1 if the input and output formats are too
* Returns the number of conversions required by the first part - 0 if only * similar to split the conversion.
* one conversion was asked. */
* Beware : p_output_format can be modified during this function if the static int SplitConversion( const audio_sample_format_t *restrict infmt,
* developer passed SplitConversion( toto, titi, titi, ... ). That is legal. const audio_sample_format_t *restrict outfmt,
* SplitConversion( toto, titi, toto, ... ) isn't. audio_sample_format_t *midfmt )
*****************************************************************************/
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 )
{ {
bool b_format = *midfmt = *outfmt;
(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) ); if( infmt->i_rate != outfmt->i_rate )
midfmt->i_rate = infmt->i_rate;
if ( i_nb_conversions == 2 ) else
{ if( infmt->i_physical_channels != outfmt->i_physical_channels
if ( !b_format || !b_channels ) || infmt->i_original_channels != outfmt->i_original_channels )
{ {
p_middle_format->i_rate = p_input_format->i_rate; midfmt->i_physical_channels = infmt->i_physical_channels;
aout_FormatPrepare( p_middle_format ); midfmt->i_original_channels = infmt->i_original_channels;
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;
} }
else
return -1;
/* i_nb_conversion == 3 */ aout_FormatPrepare( midfmt );
p_middle_format->i_rate = p_input_format->i_rate; return AOUT_FMTS_IDENTICAL( infmt, midfmt ) ? -1 : 0;
aout_FormatPrepare( p_middle_format );
return 2;
} }
static void ReleaseFilter( filter_t * p_filter ) /**
* 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 )
{ {
module_unneed( p_filter, p_filter->p_module ); audio_sample_format_t curfmt = *outfmt;
vlc_object_release( p_filter ); unsigned i = 0, max = *nb_filters - AOUT_MAX_FILTERS;
}
/***************************************************************************** filters += *nb_filters;
* aout_FiltersCreatePipeline: create a filters pipeline to transform a sample aout_FormatsPrint( obj, "filter(s)", infmt, outfmt );
* 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 )
{
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 ) ) while( !AOUT_FMTS_IDENTICAL( infmt, &curfmt ) )
{ {
msg_Dbg( p_aout, "no need for any filter" ); if( i >= max )
return 0;
}
aout_FormatsPrint( p_aout, "filter(s)", p_input_format, p_output_format );
if( *pi_nb_filters + 1 > AOUT_MAX_FILTERS )
{ {
msg_Err( p_aout, "max filter reached (%d)", AOUT_MAX_FILTERS ); msg_Err( obj, "max (%u) filters reached", AOUT_MAX_FILTERS );
dialog_Fatal( p_aout, _("Audio filtering failed"), dialog_Fatal( obj, _("Audio filtering failed"),
_("The maximum number of filters (%d) was reached."), _("The maximum number of filters (%u) was reached."),
AOUT_MAX_FILTERS ); AOUT_MAX_FILTERS );
return -1; goto rollback;
} }
/* Try to find a filter to do the whole conversion. */ /* Make room and prepend a filter */
pp_filters[0] = FindFilter( p_aout, p_input_format, p_output_format ); memmove( filters + 1, filters, i * sizeof( *filters ) );
if ( pp_filters[0] != NULL )
{
msg_Dbg( p_aout, "found a filter for the whole conversion" );
++*pi_nb_filters;
return 0;
}
/* We'll have to split the conversion. We always do the downmixing *filters = FindFilter( obj, infmt, &curfmt );
* before the resampling, because the audio decoder can probably do it if( *filters != NULL )
* 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. */ i++;
msg_Err( p_aout, "couldn't find a filter for the conversion " break; /* done! */
"%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 ); audio_sample_format_t midfmt;
if ( pp_filters[0] == NULL && i_nb_conversions == 2 ) /* Split the conversion */
{ if( SplitConversion( infmt, &curfmt, &midfmt ) )
/* 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, msg_Err( obj, "conversion pipeline failed: %4.4s -> %4.4s",
"couldn't find a filter for the first part of the conversion" ); (const char *)&infmt->i_format,
return -1; (const char *)&outfmt->i_format );
goto rollback;
} }
/* We have the first stage of the conversion. Find a filter for *filters = FindFilter( obj, &midfmt, &curfmt );
* the rest. */ if( *filters == NULL )
if( *pi_nb_filters + 2 > AOUT_MAX_FILTERS )
{ {
ReleaseFilter( pp_filters[0] ); msg_Err( obj, "cannot find filter for simple conversion" );
msg_Err( p_aout, "max filter reached (%d)", AOUT_MAX_FILTERS ); goto rollback;
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, curfmt = midfmt;
p_output_format ); i++;
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 )
{
ReleaseFilter( pp_filters[0] );
msg_Err( p_aout,
"couldn't find a filter for the second part of the conversion" );
return -1;
}
if( *pi_nb_filters + 3 > 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,
&temp_format );
pp_filters[2] = FindFilter( p_aout, &temp_format,
p_output_format );
if ( pp_filters[1] == NULL || pp_filters[2] == 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;
}
*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" );
} }
msg_Dbg( obj, "conversion pipeline completed" );
*nb_filters += i;
return 0; 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