AAC ADTS parser: parse program_config_element in frame for channel detection

The `program_config_element` (PCE) in the frame is authoritative
regarding the number of channels encoded in the frame. The container
information might be wrong (e.g. the ADTS headers containing a channel
configuration of 0, which is invalid). Therefore parse the PCE if it's
located at the start of the frame and override the ADTS header
content.

Fixes #2107.
This commit is contained in:
Moritz Bunkus 2017-10-01 20:18:54 +02:00
parent 515b3b2fae
commit 958af14d27
5 changed files with 37 additions and 1 deletions

10
NEWS.md
View File

@ -1,3 +1,13 @@
# Version ?
## Bug fixes
* mkvmerge: AAC ADTS parser: mkvmerge will now parse the
`program_config_element` if it is located at the start of an AAC frame in
order to determine the actual number of channels. This overrides invalid
channel configurations in the ADTS headers, for example. Fixes #2107.
# Version 16.0.0 "Protest" 2017-09-30
## New features and enhancements

View File

@ -111,7 +111,7 @@ create_audio_specific_config(audio_config_t const &audio_config) {
write_object_type(audio_config.profile + 1);
write_sampling_frequency(audio_config.sample_rate);
w.put_bits(4, audio_config.channels);
w.put_bits(4, audio_config.channels == 8 ? 7 : audio_config.channels);
if (audio_config.ga_specific_config && audio_config.ga_specific_config_bit_size) {
bit_reader_c r{audio_config.ga_specific_config->get_buffer(), audio_config.ga_specific_config->get_size()};
@ -564,6 +564,11 @@ parser_c::decode_adts_header(unsigned char const *buffer,
if (frame.m_header.bytes <= frame.m_header.header_byte_size)
return { failure, 1 };
auto data_start_position = bc.get_bit_position();
if (bc.get_bits(3) == 0x05)
frame.m_header.parse_program_config_element(bc);
bc.set_bit_position(data_start_position);
if (m_copy_data) {
frame.m_data = memory_c::alloc(frame.m_header.data_byte_size);
bc.get_bytes(frame.m_data->get_buffer(), frame.m_header.data_byte_size);
@ -1100,6 +1105,20 @@ header_c::parse_audio_specific_config(const unsigned char *data,
parse_audio_specific_config(bc, look_for_sync_extension);
}
void
header_c::parse_program_config_element(bit_reader_c &bc) {
m_bc = &bc;
try {
read_program_config_element();
} catch (mtx::exception &ex) {
mxdebug_if(s_debug_parse_data, boost::format("aac::parse_audio_specific_config: exception: %1%\n") % ex);
}
m_bc = nullptr;
}
bool
operator ==(const header_c &h1,
const header_c &h2) {

View File

@ -91,6 +91,7 @@ public:
void parse_audio_specific_config(const unsigned char *data, size_t size, bool look_for_sync_extension = true);
void parse_audio_specific_config(bit_reader_c &bc, bool look_for_sync_extension = true);
void parse_program_config_element(bit_reader_c &bc);
protected:
int read_object_type();

View File

@ -462,3 +462,4 @@ T_613vorbis_in_mp4:bcf052d24ed82ff0de57425259d075db:passed:20170910-175618:0.014
T_614white_colour_coordinates_from_mkv:916ae39f45a435c0b526d875c378e199-916ae39f45a435c0b526d875c378e199:passed:20170916-112249:0.094985684
T_615opus_discard_padding_in_the_middle:1b2e18413bab72c0d669a406fc403b38:passed:20170924-230527:0.025602623
T_616more_than_128_tracks:221a656c73308a4d530fb2cbf3fd339c-221a656c73308a4d530fb2cbf3fd339c:passed:20170925-201313:0.570145315
T_617aac_adts_parse_program_config_element_for_channels:87463bd00d95fb4d8311e81e871f61e5:passed:20171001-201657:0.037546681

View File

@ -0,0 +1,5 @@
#!/usr/bin/ruby -w
# T_617aac_adts_parse_program_config_element_for_channels
describe "mkvmerge / AAC in ADTS with channel_config == 0, but with program_config_element at start signalling 7.1 channels"
test_merge "data/aac/adts_0_channels_but_program_config_element_at_start.aac"