vlc | branch: master | Rémi Denis-Courmont <[email protected]> | Thu Nov 15 22:37:36 2012 +0200| [3a2ba96b99e5ea08212759e5c5845f6054584f03] | committer: Rémi Denis-Courmont
aout: rewrite and robustify conversion pipelines This should fix problems when remixing is required but the FL32 format is not involved, as well as decoding on non-FPU platforms. This also disables (or rather avoids) remixing in A52 and DTS decoders. I do not really see the point in using the A52 downmixer anyway. > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=3a2ba96b99e5ea08212759e5c5845f6054584f03 --- src/audio_output/filters.c | 220 +++++++++++++++++++++++++++----------------- 1 file changed, 137 insertions(+), 83 deletions(-) diff --git a/src/audio_output/filters.c b/src/audio_output/filters.c index 14f9e66..bd4dbbb 100644 --- a/src/audio_output/filters.c +++ b/src/audio_output/filters.c @@ -83,50 +83,6 @@ static filter_t * FindFilter( vlc_object_t *obj, } /** - * 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 ) -{ - *midfmt = *outfmt; - - /* Lastly: resample (after format conversion and remixing) */ - if( infmt->i_rate != outfmt->i_rate ) - midfmt->i_rate = infmt->i_rate; - else - /* Penultimately: remix channels (after format conversion) */ - if( infmt->i_physical_channels != outfmt->i_physical_channels - || infmt->i_original_channels != outfmt->i_original_channels ) - { - midfmt->i_physical_channels = infmt->i_physical_channels; - midfmt->i_original_channels = infmt->i_original_channels; - } - else - /* Second: convert linear to S16N as intermediate format */ - if( AOUT_FMT_LINEAR( infmt ) ) - { - /* All conversion from linear to S16N must be supported directly. */ - if( outfmt->i_format == VLC_CODEC_S16N ) - return -1; - midfmt->i_format = VLC_CODEC_S16N; - } - else - /* First: convert non-linear to FI32 as intermediate format */ - { - if( outfmt->i_format == VLC_CODEC_FI32 ) - return -1; - midfmt->i_format = VLC_CODEC_FI32; - } - - assert( !AOUT_FMTS_IDENTICAL( infmt, midfmt ) ); - aout_FormatPrepare( midfmt ); - return 0; -} - -/** * Destroys a chain of audio filters. */ static void aout_FiltersPipelineDestroy(filter_t *const *filters, unsigned n) @@ -140,77 +96,175 @@ static void aout_FiltersPipelineDestroy(filter_t *const *filters, unsigned n) } } +static filter_t *TryFormat (vlc_object_t *obj, vlc_fourcc_t codec, + audio_sample_format_t *restrict fmt) +{ + audio_sample_format_t output = *fmt; + + assert (codec != fmt->i_format); + output.i_format = codec; + aout_FormatPrepare (&output); + + filter_t *filter = FindFilter (obj, fmt, &output); + if (filter != NULL) + *fmt = output; + return 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 max_filters size of filters table [IN] + * @param count pointer to the number of filters in the table [IN/OUT] + * @param max size of filters table [IN] * @param infmt input audio format * @param outfmt output audio format * @return 0 on success, -1 on failure */ static int aout_FiltersPipelineCreate(vlc_object_t *obj, filter_t **filters, - unsigned *nb_filters, unsigned max_filters, + unsigned *count, unsigned max, const audio_sample_format_t *restrict infmt, const audio_sample_format_t *restrict outfmt) { - audio_sample_format_t curfmt = *outfmt; - unsigned i = 0; - - max_filters -= *nb_filters; - filters += *nb_filters; - aout_FormatsPrint( obj, "filter(s)", infmt, outfmt ); + aout_FormatsPrint (obj, "conversion:", infmt, outfmt); + max -= *count; + filters += *count; + + /* There is a lot of second guessing on what the conversion plugins can + * and cannot do. This seems hardly avoidable, the conversion problem need + * to be reduced somehow. */ + audio_sample_format_t input = *infmt; + bool same_codec = infmt->i_format == outfmt->i_format; + bool same_rate = infmt->i_rate == outfmt->i_rate; + bool same_mix = infmt->i_physical_channels == outfmt->i_physical_channels + && infmt->i_original_channels == outfmt->i_original_channels; + unsigned n = 0; - while( !AOUT_FMTS_IDENTICAL( infmt, &curfmt ) ) + /* Encapsulate or decode non-linear formats */ + if (!AOUT_FMT_LINEAR(infmt) && !same_codec) { - if( i >= max_filters ) + if (n == max) + goto overflow; + + filter_t *f = NULL; + if (!AOUT_FMT_LINEAR(outfmt)) + f = TryFormat (obj, outfmt->i_format, &input); + if (f == NULL) + f = TryFormat (obj, VLC_CODEC_FI32, &input); + if (f == NULL) + f = TryFormat (obj, VLC_CODEC_FL32, &input); + if (f == NULL) { - msg_Err( obj, "maximum of %u filters reached", max_filters ); - dialog_Fatal( obj, _("Audio filtering failed"), - _("The maximum number of filters (%u) was reached."), - max_filters ); - goto rollback; + msg_Err (obj, "cannot find %s for conversion pipeline", + "decoder"); + goto error; } - /* Make room and prepend a filter */ - memmove( filters + 1, filters, i * sizeof( *filters ) ); + filters[n++] = f; + same_codec = input.i_format == outfmt->i_format; + } + + assert (AOUT_FMT_LINEAR(&input)); + + /* Conversion cannot be done in foreign endianess. */ + /* TODO: convert to native endian if needed */ - *filters = FindFilter( obj, infmt, &curfmt ); - if( *filters != NULL ) + /* Remix channels */ + if (!same_mix) + { /* Remixing currently requires FL32... TODO: S16N */ + if (input.i_format != VLC_CODEC_FL32) { - i++; - break; /* done! */ + if (n == max) + goto overflow; + + filter_t *f = TryFormat (obj, VLC_CODEC_FL32, &input); + if (f == NULL) + { + msg_Err (obj, "cannot find %s for conversion pipeline", + "pre-mix converter"); + goto error; + } + + filters[n++] = f; + same_codec = input.i_format == outfmt->i_format; } - audio_sample_format_t midfmt; - /* Split the conversion */ - if( SplitConversion( infmt, &curfmt, &midfmt ) ) + if (n == max) + goto overflow; + + audio_sample_format_t output; + output.i_format = input.i_format; + output.i_rate = input.i_rate; + output.i_physical_channels = outfmt->i_physical_channels; + output.i_original_channels = outfmt->i_original_channels; + aout_FormatPrepare (&output); + + filter_t *f = FindFilter (obj, &input, &output); + if (f == NULL) { - msg_Err( obj, "conversion pipeline failed: %4.4s -> %4.4s", - (const char *)&infmt->i_format, - (const char *)&outfmt->i_format ); - goto rollback; + msg_Err (obj, "cannot find %s for conversion pipeline", + "remixer"); + goto error; } - *filters = FindFilter( obj, &midfmt, &curfmt ); - if( *filters == NULL ) + input = output; + filters[n++] = f; + //same_mix = true; + } + + /* Resample */ + if (!same_rate) + { /* Resampling works with any linear format, but may be ugly. */ + if (n == max) + goto overflow; + + audio_sample_format_t output = input; + output.i_rate = outfmt->i_rate; + + filter_t *f = FindFilter (obj, &input, &output); + if (f == NULL) { - msg_Err( obj, "cannot find filter for simple conversion" ); - goto rollback; + msg_Err (obj, "cannot find %s for conversion pipeline", + "resampler"); + goto error; } - curfmt = midfmt; - i++; + + input = output; + filters[n++] = f; + //same_rate = true; + } + + if (!same_codec) + { + if (max == 0) + goto overflow; + + filter_t *f = TryFormat (obj, outfmt->i_format, &input); + if (f == NULL) + { + msg_Err (obj, "cannot find %s for conversion pipeline", + "post-mix converter"); + goto error; + } + filters[n++] = f; + //same_codec = true; } - msg_Dbg( obj, "conversion pipeline completed" ); - *nb_filters += i; + /* TODO: convert to foreign endian if needed */ + + msg_Dbg (obj, "conversion pipeline complete"); + *count += n; return 0; -rollback: - aout_FiltersPipelineDestroy (filters, i); +overflow: + msg_Err (obj, "maximum of %u conversion filters reached", max); + dialog_Fatal (obj, _("Audio filtering failed"), + _("The maximum number of filters (%u) was reached."), max); +error: + aout_FiltersPipelineDestroy (filters, n); return -1; } + #define aout_FiltersPipelineCreate(obj,f,n,m,i,o) \ aout_FiltersPipelineCreate(VLC_OBJECT(obj),f,n,m,i,o) _______________________________________________ vlc-commits mailing list [email protected] http://mailman.videolan.org/listinfo/vlc-commits
