[vlc-devel] [PATCH] Backport fixes for audio resampling or downmixing from master.
Alexis Ballier
aballier at gentoo.org
Sat Feb 28 13:51:32 CET 2009
From: Laurent Aimar <fenrir at videolan.org>
Fixed audio transcoding when channel mixing or resampling is needed.
Signed-off-by: Alexis Ballier <aballier at gentoo.org>
---
modules/stream_out/transcode.c | 238 +++++++++++++++++++++-------------------
1 files changed, 123 insertions(+), 115 deletions(-)
diff --git a/modules/stream_out/transcode.c b/modules/stream_out/transcode.c
index 7290b60..da60d1c 100644
--- a/modules/stream_out/transcode.c
+++ b/modules/stream_out/transcode.c
@@ -1101,12 +1101,107 @@ static int transcode_audio_filter_allocation_init( filter_t *p_filter,
return VLC_SUCCESS;
}
+static bool transcode_audio_filter_needed( const es_format_t *p_fmt1, const es_format_t *p_fmt2 )
+{
+ if( p_fmt1->i_codec != p_fmt2->i_codec ||
+ p_fmt1->audio.i_channels != p_fmt2->audio.i_channels ||
+ p_fmt1->audio.i_rate != p_fmt2->audio.i_rate )
+ return true;
+ return false;
+}
+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_FOURCC('f','l','3','2') )
+ {
+ /* First step, convert to fl32 */
+ current.i_codec =
+ current.audio.i_format = VLC_FOURCC('f','l','3','2');
+
+ 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;
+ 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];
+
+ 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;
+ 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;
+}
+
static int transcode_audio_new( sout_stream_t *p_stream,
sout_stream_id_t *id )
{
sout_stream_sys_t *p_sys = p_stream->p_sys;
es_format_t fmt_last;
- int i;
/*
* Open decoder
@@ -1172,130 +1267,39 @@ static int transcode_audio_new( sout_stream_t *p_stream,
id->p_encoder->fmt_in.audio.i_bitspersample =
aout_BitsPerSample( id->p_encoder->fmt_in.i_codec );
- /* Init filter chain */
- id->p_f_chain = filter_chain_New( p_stream, "audio filter2", true,
- transcode_audio_filter_allocation_init, NULL, NULL );
- filter_chain_Reset( id->p_f_chain, &fmt_last, &id->p_encoder->fmt_in );
-
- /* Load conversion filters */
- if( fmt_last.audio.i_channels != id->p_encoder->fmt_in.audio.i_channels ||
- fmt_last.audio.i_rate != id->p_encoder->fmt_in.audio.i_rate )
- {
- /* We'll have to go through fl32 first */
- fmt_last.i_codec = fmt_last.audio.i_format = VLC_FOURCC('f','l','3','2');
- fmt_last.audio.i_bitspersample = aout_BitsPerSample( fmt_last.i_codec );
- filter_chain_AppendFilter( id->p_f_chain, NULL, NULL, NULL, &fmt_last );
- fmt_last = *filter_chain_GetFmtOut( id->p_f_chain );
- }
-
- for( i = 0; i < 4; i++ )
- {
- if( (fmt_last.audio.i_channels !=
- id->p_encoder->fmt_in.audio.i_channels) ||
- (fmt_last.audio.i_rate != id->p_encoder->fmt_in.audio.i_rate) ||
- (fmt_last.i_codec != id->p_encoder->fmt_in.i_codec) )
- {
- msg_Dbg( p_stream, "Looking for filter "
- "(%4.4s->%4.4s, channels %d->%d, rate %d->%d)",
- (char *)&fmt_last.i_codec,
- (char *)&id->p_encoder->fmt_in.i_codec,
- fmt_last.audio.i_channels,
- id->p_encoder->fmt_in.audio.i_channels,
- fmt_last.audio.i_rate,
- id->p_encoder->fmt_in.audio.i_rate );
- filter_chain_AppendFilter( id->p_f_chain, NULL, NULL,
- &fmt_last, &id->p_encoder->fmt_in );
- fmt_last = *filter_chain_GetFmtOut( id->p_f_chain );
- }
- else break;
- }
-
- /* Final checks to see if conversions were successful */
- if( fmt_last.i_codec != id->p_encoder->fmt_in.i_codec )
- {
- msg_Err( p_stream, "no audio filter found "
- "(%4.4s->%4.4s, channels %d->%d, rate %d->%d)",
- (char *)&fmt_last.i_codec,
- (char *)&id->p_encoder->fmt_in.i_codec,
- fmt_last.audio.i_channels,
- id->p_encoder->fmt_in.audio.i_channels,
- fmt_last.audio.i_rate,
- id->p_encoder->fmt_in.audio.i_rate );
- transcode_audio_close( id );
- return VLC_EGENERIC;
- }
-
- /* Load user specified audio filters now */
+ /* Load user specified audio filters */
if( p_sys->psz_af2 )
{
- id->p_uf_chain = filter_chain_New( p_stream, "audio filter2", false,
- transcode_audio_filter_allocation_init, NULL, NULL );
- filter_chain_Reset( id->p_uf_chain, &fmt_last, &id->p_encoder->fmt_in );
- filter_chain_AppendFromString( id->p_uf_chain, p_sys->psz_af2 );
- fmt_last = *filter_chain_GetFmtOut( id->p_uf_chain );
- }
-
- if( fmt_last.audio.i_channels != id->p_encoder->fmt_in.audio.i_channels )
- {
-#if 1
- module_Unneed( id->p_encoder, id->p_encoder->p_module );
- id->p_encoder->p_module = NULL;
-
- /* This might work, but only if the encoder is restarted */
- id->p_encoder->fmt_in.audio.i_channels = fmt_last.audio.i_channels;
- id->p_encoder->fmt_out.audio.i_channels = fmt_last.audio.i_channels;
-
- id->p_encoder->fmt_in.audio.i_physical_channels =
- id->p_encoder->fmt_in.audio.i_original_channels =
- fmt_last.audio.i_physical_channels;
- id->p_encoder->fmt_out.audio.i_physical_channels =
- id->p_encoder->fmt_out.audio.i_original_channels =
- fmt_last.audio.i_physical_channels;
-
- msg_Dbg( p_stream, "number of audio channels for mixing changed, "
- "trying to reopen the encoder for mixing %i to %i channels",
- fmt_last.audio.i_channels,
- id->p_encoder->fmt_in.audio.i_channels );
-
- /* reload encoder */
- 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 )
+ es_format_t fmt_fl32 = fmt_last;
+ fmt_fl32.i_codec =
+ fmt_fl32.audio.i_format = VLC_FOURCC('f','l','3','2');
+ if( transcode_audio_filter_chain_build( p_stream, id->p_uf_chain,
+ &fmt_fl32, &fmt_last ) )
{
- msg_Err( p_stream, "cannot find audio encoder (module:%s fourcc:%4.4s)",
- p_sys->psz_aenc ? p_sys->psz_aenc : "any",
- (char *)&p_sys->i_acodec );
transcode_audio_close( id );
return VLC_EGENERIC;
}
- id->p_encoder->fmt_in.audio.i_format = id->p_encoder->fmt_in.i_codec;
- id->p_encoder->fmt_in.audio.i_bitspersample =
- aout_BitsPerSample( id->p_encoder->fmt_in.i_codec );
-#else
- msg_Err( p_stream, "no audio filter found for mixing from"
- " %i to %i channels", fmt_last.audio.i_channels,
- id->p_encoder->fmt_in.audio.i_channels );
+ fmt_last = fmt_fl32;
- transcode_audio_close( id );
- return VLC_EGENERIC;
-#endif
+ id->p_uf_chain = filter_chain_New( p_stream, "audio filter2", false,
+ transcode_audio_filter_allocation_init, NULL, NULL );
+ filter_chain_Reset( id->p_uf_chain, &fmt_last, &fmt_fl32 );
+ if( filter_chain_AppendFromString( id->p_uf_chain, p_sys->psz_af2 ) > 0 )
+ fmt_last = *filter_chain_GetFmtOut( id->p_uf_chain );
}
- if( fmt_last.audio.i_rate != id->p_encoder->fmt_in.audio.i_rate )
+ /* Load conversion filters */
+ id->p_f_chain = filter_chain_New( p_stream, "audio filter2", true,
+ transcode_audio_filter_allocation_init, NULL, NULL );
+ filter_chain_Reset( id->p_f_chain, &fmt_last, &id->p_encoder->fmt_in );
+
+ if( transcode_audio_filter_chain_build( p_stream, id->p_f_chain,
+ &id->p_encoder->fmt_in, &fmt_last ) )
{
- msg_Err( p_stream, "no audio filter found for resampling from"
- " %iHz to %iHz", fmt_last.audio.i_rate,
- id->p_encoder->fmt_in.audio.i_rate );
-#if 0
- /* FIXME : this might work, but only if the encoder is restarted */
- id->p_encoder->fmt_in.audio.i_rate = fmt_last.audio.i_rate;
- id->p_encoder->fmt_out.audio.i_rate = fmt_last.audio.i_rate;
-#else
transcode_audio_close( id );
return VLC_EGENERIC;
-#endif
}
+ fmt_last = id->p_encoder->fmt_in;
/* FIXME: Hack for mp3 transcoding support */
if( id->p_encoder->fmt_out.i_codec == VLC_FOURCC( 'm','p','3',' ' ) )
@@ -1319,10 +1323,10 @@ static void transcode_audio_close( sout_stream_id_t *id )
id->p_encoder->p_module = NULL;
/* Close filters */
- if( id->p_f_chain )
- filter_chain_Delete( id->p_f_chain );
if( id->p_uf_chain )
filter_chain_Delete( id->p_uf_chain );
+ if( id->p_f_chain )
+ filter_chain_Delete( id->p_f_chain );
}
static int transcode_audio_process( sout_stream_t *p_stream,
@@ -1363,9 +1367,13 @@ static int transcode_audio_process( sout_stream_t *p_stream,
p_audio_block->i_samples = p_audio_buf->i_nb_samples;
/* Run filter chain */
- p_audio_block = filter_chain_AudioFilter( id->p_f_chain, p_audio_block );
if( id->p_uf_chain )
+ {
p_audio_block = filter_chain_AudioFilter( id->p_uf_chain, p_audio_block );
+ assert( p_audio_block );
+ }
+
+ p_audio_block = filter_chain_AudioFilter( id->p_f_chain, p_audio_block );
assert( p_audio_block );
p_audio_buf->p_buffer = p_audio_block->p_buffer;
--
1.6.1.3
More information about the vlc-devel
mailing list