[vlc-devel] [PATCH] avcodec: Re-prepare on audio sample format change (DTS-HD)
Jack Andersen
jackoalan at gmail.com
Fri Oct 18 09:35:51 CEST 2019
I have encountered an edge case in the avcodec module while playing DTS-HD
tracks on a BDMV title (specifically Star Trek: TNG during the DTS trailer).
Decoded DTS blocks may alternate between HD and non-HD formats and VLC
currently does not fully handle this transition. DTS-HD blocks are decoded to
a 32-bit-per-sample format by libavcodec, and non-HD blocks are decoded to a
16-bit format. When a 32->16 transition occurs, the interleaving buffers are
correctly shrunk, but the i_bitspersample field remains at 32-bits. This
ultimately causes a segfault when half of the interleaving buffer has been
processed.
VLC already responds to changes in the channel layout. This patch
additionally detects for changes in the sample format.
---
modules/codec/avcodec/audio.c | 110 ++++++++++++++++++----------------
1 file changed, 60 insertions(+), 50 deletions(-)
diff --git a/modules/codec/avcodec/audio.c b/modules/codec/avcodec/audio.c
index 27d4e511f6..32ef88e754 100644
--- a/modules/codec/avcodec/audio.c
+++ b/modules/codec/avcodec/audio.c
@@ -65,6 +65,7 @@ typedef struct
int pi_extraction[AOUT_CHAN_MAX];
int i_previous_channels;
uint64_t i_previous_layout;
+ vlc_fourcc_t i_previous_codec;
} decoder_sys_t;
#define BLOCK_FLAG_PRIVATE_REALLOCATED (1 << BLOCK_FLAG_PRIVATE_SHIFT)
@@ -250,6 +251,7 @@ int InitAudioDec( vlc_object_t *obj )
p_sys->b_extract = false;
p_sys->i_previous_channels = 0;
p_sys->i_previous_layout = 0;
+ p_sys->i_previous_codec = 0;
/* */
/* Try to set as much information as possible but do not trust it */
@@ -587,67 +589,75 @@ static void SetupOutputFormat( decoder_t *p_dec, bool b_trust )
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 )
+ bool b_channel_layout_changed =
+ p_sys->i_previous_channels != p_sys->p_context->channels ||
+ p_sys->i_previous_layout != p_sys->p_context->channel_layout;
+ if( b_channel_layout_changed )
{
- p_sys->i_previous_channels = p_sys->p_context->channels;
- p_sys->i_previous_layout = p_sys->p_context->channel_layout;
- }
+ if( b_trust )
+ {
+ p_sys->i_previous_channels = p_sys->p_context->channels;
+ p_sys->i_previous_layout = p_sys->p_context->channel_layout;
+ }
- const unsigned i_order_max = sizeof(pi_channels_map)/sizeof(*pi_channels_map);
- uint32_t pi_order_src[i_order_max];
+ const unsigned i_order_max = sizeof(pi_channels_map)/sizeof(*pi_channels_map);
+ uint32_t pi_order_src[i_order_max];
- int i_channels_src = 0;
- uint64_t channel_layout =
- p_sys->p_context->channel_layout ? p_sys->p_context->channel_layout :
- (uint64_t)av_get_default_channel_layout( p_sys->p_context->channels );
+ int i_channels_src = 0;
+ uint64_t channel_layout =
+ p_sys->p_context->channel_layout ? p_sys->p_context->channel_layout :
+ (uint64_t)av_get_default_channel_layout( p_sys->p_context->channels );
- if( channel_layout )
- {
- for( unsigned i = 0; i < i_order_max
- && i_channels_src < p_sys->p_context->channels; i++ )
+ if( channel_layout )
{
- if( channel_layout & pi_channels_map[i][0] )
- pi_order_src[i_channels_src++] = pi_channels_map[i][1];
- }
+ for( unsigned i = 0; i < i_order_max
+ && i_channels_src < p_sys->p_context->channels; i++ )
+ {
+ if( channel_layout & pi_channels_map[i][0] )
+ 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" );
- if( i_channels_src != p_sys->p_context->channels && b_trust )
- msg_Err( p_dec, "Channel layout not understood" );
+ /* Detect special dual mono case */
+ if( i_channels_src == 2 && pi_order_src[0] == AOUT_CHAN_CENTER
+ && pi_order_src[1] == AOUT_CHAN_CENTER )
+ {
+ p_dec->fmt_out.audio.i_chan_mode |= AOUT_CHANMODE_DUALMONO;
+ pi_order_src[0] = AOUT_CHAN_LEFT;
+ pi_order_src[1] = AOUT_CHAN_RIGHT;
+ }
- /* Detect special dual mono case */
- if( i_channels_src == 2 && pi_order_src[0] == AOUT_CHAN_CENTER
- && pi_order_src[1] == AOUT_CHAN_CENTER )
+ 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 );
+
+ /* No reordering for Ambisonic order 1 channels encoded in AAC... */
+ if (p_dec->fmt_out.audio.channel_type == AUDIO_CHANNEL_TYPE_AMBISONICS
+ && p_dec->fmt_in.i_codec == VLC_CODEC_MP4A
+ && i_channels_src == 4)
+ p_sys->b_extract = false;
+
+ p_dec->fmt_out.audio.i_physical_channels = i_layout_dst;
+ }
+ else
{
- p_dec->fmt_out.audio.i_chan_mode |= AOUT_CHANMODE_DUALMONO;
- pi_order_src[0] = AOUT_CHAN_LEFT;
- pi_order_src[1] = AOUT_CHAN_RIGHT;
+ msg_Warn( p_dec, "no channel layout found");
+ p_dec->fmt_out.audio.i_physical_channels = 0;
+ p_dec->fmt_out.audio.i_channels = p_sys->p_context->channels;
}
-
- 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 );
-
- /* No reordering for Ambisonic order 1 channels encoded in AAC... */
- if (p_dec->fmt_out.audio.channel_type == AUDIO_CHANNEL_TYPE_AMBISONICS
- && p_dec->fmt_in.i_codec == VLC_CODEC_MP4A
- && i_channels_src == 4)
- p_sys->b_extract = false;
-
- p_dec->fmt_out.audio.i_physical_channels = i_layout_dst;
}
- else
+
+ if( b_channel_layout_changed || p_sys->i_previous_codec != p_dec->fmt_out.i_codec )
{
- msg_Warn( p_dec, "no channel layout found");
- p_dec->fmt_out.audio.i_physical_channels = 0;
- p_dec->fmt_out.audio.i_channels = p_sys->p_context->channels;
+ if( b_trust )
+ p_sys->i_previous_codec = p_dec->fmt_out.i_codec;
+ aout_FormatPrepare( &p_dec->fmt_out.audio );
}
-
- aout_FormatPrepare( &p_dec->fmt_out.audio );
}
--
2.23.0
More information about the vlc-devel
mailing list