From 0a69779f7c6401a3f429e53e4cbeb9138af0703b Mon Sep 17 00:00:00 2001 From: KongQun Yang Date: Mon, 6 Nov 2017 15:45:44 -0800 Subject: [PATCH] Fix a parsing problem with AC3 in TS Audio samples per frame for AC3 was not specified correctly earlier. Also the number of channels is not correct if LFE channel is on. Issue #165 Change-Id: Ibf20aa4c7aec43c07ec7cd394d631c537cb387dd --- packager/media/demuxer/demuxer.gyp | 1 - packager/media/formats/mp2t/ac3_header.cc | 10 +++++- packager/media/formats/mp2t/ac3_header.h | 1 + .../media/formats/mp2t/ac3_header_unittest.cc | 33 +++++++++++++++++++ packager/media/formats/mp2t/adts_header.cc | 22 ++++++++++++- packager/media/formats/mp2t/adts_header.h | 1 + packager/media/formats/mp2t/audio_header.h | 3 ++ .../media/formats/mp2t/es_parser_audio.cc | 7 ++-- packager/media/formats/mp2t/mp2t.gyp | 1 - packager/media/formats/mpeg/adts_constants.cc | 26 --------------- packager/media/formats/mpeg/adts_constants.h | 27 --------------- packager/media/formats/mpeg/mpeg.gyp | 33 ------------------- packager/media/formats/wvm/wvm.gyp | 1 - packager/packager.gyp | 1 - 14 files changed, 71 insertions(+), 96 deletions(-) delete mode 100644 packager/media/formats/mpeg/adts_constants.cc delete mode 100644 packager/media/formats/mpeg/adts_constants.h delete mode 100644 packager/media/formats/mpeg/mpeg.gyp diff --git a/packager/media/demuxer/demuxer.gyp b/packager/media/demuxer/demuxer.gyp index 788a76ed56..80492e86fd 100644 --- a/packager/media/demuxer/demuxer.gyp +++ b/packager/media/demuxer/demuxer.gyp @@ -20,7 +20,6 @@ '../base/media_base.gyp:media_base', '../formats/mp2t/mp2t.gyp:mp2t', '../formats/mp4/mp4.gyp:mp4', - '../formats/mpeg/mpeg.gyp:mpeg', '../formats/webm/webm.gyp:webm', '../formats/webvtt/webvtt.gyp:webvtt', '../formats/wvm/wvm.gyp:wvm', diff --git a/packager/media/formats/mp2t/ac3_header.cc b/packager/media/formats/mp2t/ac3_header.cc index 757a8da73e..2cf959356e 100644 --- a/packager/media/formats/mp2t/ac3_header.cc +++ b/packager/media/formats/mp2t/ac3_header.cc @@ -43,6 +43,7 @@ const size_t kFrameSizeCodeTable[][3] = { bool Ac3Header::IsSyncWord(const uint8_t* buf) const { DCHECK(buf); + // ATSC Standard A/52:2012 5.4.1 syncinfo: Synchronization Information. return buf[0] == 0x0B && buf[1] == 0x77; } @@ -52,6 +53,13 @@ size_t Ac3Header::GetMinFrameSize() const { return kMinAc3FrameSize; } +size_t Ac3Header::GetSamplesPerFrame() const { + // ATSC Standard A/52:2012 + // Annex A: AC-3 Elementary Streams in the MPEG-2 Multiplex. + const size_t kSamplesPerAc3Frame = 1536; + return kSamplesPerAc3Frame; +} + bool Ac3Header::Parse(const uint8_t* audio_frame, size_t audio_frame_size) { BitReader frame(audio_frame, audio_frame_size); @@ -127,7 +135,7 @@ uint32_t Ac3Header::GetSamplingFrequency() const { uint8_t Ac3Header::GetNumChannels() const { DCHECK_LT(acmod_, arraysize(kAc3NumChannelsTable)); - return kAc3NumChannelsTable[acmod_]; + return kAc3NumChannelsTable[acmod_] + (lfeon_ ? 1 : 0); } } // namespace mp2t diff --git a/packager/media/formats/mp2t/ac3_header.h b/packager/media/formats/mp2t/ac3_header.h index 29debb39cb..773994cb5a 100644 --- a/packager/media/formats/mp2t/ac3_header.h +++ b/packager/media/formats/mp2t/ac3_header.h @@ -28,6 +28,7 @@ class Ac3Header : public AudioHeader { /// @{ bool IsSyncWord(const uint8_t* buf) const override; size_t GetMinFrameSize() const override; + size_t GetSamplesPerFrame() const override; bool Parse(const uint8_t* adts_frame, size_t adts_frame_size) override; size_t GetHeaderSize() const override; size_t GetFrameSize() const override; diff --git a/packager/media/formats/mp2t/ac3_header_unittest.cc b/packager/media/formats/mp2t/ac3_header_unittest.cc index 9eadde2026..ade3c4acc3 100644 --- a/packager/media/formats/mp2t/ac3_header_unittest.cc +++ b/packager/media/formats/mp2t/ac3_header_unittest.cc @@ -25,6 +25,11 @@ const char kValidPartialAc3Frame[] = "000000000000000000001DDDDDDE3C78DB6DB6DB6F9F35AD6B5AD6B5AD6B5AD6B5AD6B5AD6" "9800000000000F1B6DB6DB6DE3C78F1DDD"; +const char kValidPartialAc3FrameSixChannels[] = + "0B77A3B35E40EBF8403EFF9DF0C3F8430FE1FC155755DF3E7CFA33E7CF9F3E7CF9F3E7CF9F" + "3ECDFF3ABE7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7" + "CF9F3E7CF9F3E7CF9F3E7C31F3E7CF9F3E7C7FCEAF9F3E7CF9F3"; + } // anonymous namespace namespace shaka { @@ -35,10 +40,13 @@ class Ac3HeaderTest : public testing::Test { public: void SetUp() override { ASSERT_TRUE(base::HexStringToBytes(kValidPartialAc3Frame, &ac3_frame_)); + ASSERT_TRUE(base::HexStringToBytes(kValidPartialAc3FrameSixChannels, + &ac3_frame_six_channels_)); } protected: std::vector ac3_frame_; + std::vector ac3_frame_six_channels_; }; TEST_F(Ac3HeaderTest, ParseSuccess) { @@ -65,6 +73,31 @@ TEST_F(Ac3HeaderTest, ParseSuccess) { audio_specific_config); } +TEST_F(Ac3HeaderTest, ParseMultiChannelSuccess) { + const size_t kExpectedFrameSize(1950); + const size_t kExpectedHeaderSize(0); + const uint8_t kExpectedObjectType(0); + const uint32_t kExpectedSamplingFrequency(44100); + const uint8_t kExpectedNumChannels(6); + const uint8_t kExpectedAudioSpecificConfig[] = {0x50, 0x3D, 0xE0}; + + Ac3Header ac3_header; + ASSERT_TRUE(ac3_header.Parse(ac3_frame_six_channels_.data(), + ac3_frame_six_channels_.size())); + EXPECT_EQ(kExpectedFrameSize, ac3_header.GetFrameSize()); + EXPECT_EQ(kExpectedHeaderSize, ac3_header.GetHeaderSize()); + EXPECT_EQ(kExpectedObjectType, ac3_header.GetObjectType()); + EXPECT_EQ(kExpectedSamplingFrequency, ac3_header.GetSamplingFrequency()); + EXPECT_EQ(kExpectedNumChannels, ac3_header.GetNumChannels()); + std::vector audio_specific_config; + ac3_header.GetAudioSpecificConfig(&audio_specific_config); + EXPECT_EQ(arraysize(kExpectedAudioSpecificConfig), + audio_specific_config.size()); + EXPECT_EQ(std::vector(std::begin(kExpectedAudioSpecificConfig), + std::end(kExpectedAudioSpecificConfig)), + audio_specific_config); +} + TEST_F(Ac3HeaderTest, ParseVariousDataSize) { Ac3Header ac3_header; diff --git a/packager/media/formats/mp2t/adts_header.cc b/packager/media/formats/mp2t/adts_header.cc index ef64e0fc1e..07f11cdcc7 100644 --- a/packager/media/formats/mp2t/adts_header.cc +++ b/packager/media/formats/mp2t/adts_header.cc @@ -9,7 +9,22 @@ #include "packager/media/base/bit_reader.h" #include "packager/media/base/bit_writer.h" #include "packager/media/formats/mp2t/mp2t_common.h" -#include "packager/media/formats/mpeg/adts_constants.h" + +namespace { +const size_t kAdtsHeaderMinSize = 7; + +// The following conversion table is extracted from ISO 14496 Part 3 - +// Table 1.16 - Sampling Frequency Index. +const int kAdtsFrequencyTable[] = {96000, 88200, 64000, 48000, 44100, + 32000, 24000, 22050, 16000, 12000, + 11025, 8000, 7350}; +const size_t kAdtsFrequencyTableSize = arraysize(kAdtsFrequencyTable); + +// The following conversion table is extracted from ISO 14496 Part 3 - +// Table 1.17 - Channel Configuration. +const int kAdtsNumChannelsTable[] = {0, 1, 2, 3, 4, 5, 6, 8}; +const size_t kAdtsNumChannelsTableSize = arraysize(kAdtsNumChannelsTable); +} // namespace namespace shaka { namespace media { @@ -23,6 +38,11 @@ size_t AdtsHeader::GetMinFrameSize() const { return kAdtsHeaderMinSize + 1; } +size_t AdtsHeader::GetSamplesPerFrame() const { + const size_t kSamplesPerAacFrame = 1024; + return kSamplesPerAacFrame; +} + bool AdtsHeader::Parse(const uint8_t* adts_frame, size_t adts_frame_size) { CHECK(adts_frame); diff --git a/packager/media/formats/mp2t/adts_header.h b/packager/media/formats/mp2t/adts_header.h index feb8f85706..26a7315e9c 100644 --- a/packager/media/formats/mp2t/adts_header.h +++ b/packager/media/formats/mp2t/adts_header.h @@ -28,6 +28,7 @@ class AdtsHeader : public AudioHeader { /// @{ bool IsSyncWord(const uint8_t* buf) const override; size_t GetMinFrameSize() const override; + size_t GetSamplesPerFrame() const override; bool Parse(const uint8_t* adts_frame, size_t adts_frame_size) override; size_t GetHeaderSize() const override; size_t GetFrameSize() const override; diff --git a/packager/media/formats/mp2t/audio_header.h b/packager/media/formats/mp2t/audio_header.h index 20660162c3..2808e053fa 100644 --- a/packager/media/formats/mp2t/audio_header.h +++ b/packager/media/formats/mp2t/audio_header.h @@ -29,6 +29,9 @@ class AudioHeader { /// @return The minium frame size. virtual size_t GetMinFrameSize() const = 0; + /// @return Number of audio samples per frame. + virtual size_t GetSamplesPerFrame() const = 0; + /// Parse a partial audio frame, extracting the fields within. Only audio /// frame header / metadata is parsed. The audio_frame_size must contain the /// full header / metadata. diff --git a/packager/media/formats/mp2t/es_parser_audio.cc b/packager/media/formats/mp2t/es_parser_audio.cc index 2244a978ef..9599563d73 100644 --- a/packager/media/formats/mp2t/es_parser_audio.cc +++ b/packager/media/formats/mp2t/es_parser_audio.cc @@ -19,7 +19,6 @@ #include "packager/media/formats/mp2t/adts_header.h" #include "packager/media/formats/mp2t/mp2t_common.h" #include "packager/media/formats/mp2t/ts_stream_type.h" -#include "packager/media/formats/mpeg/adts_constants.h" namespace shaka { namespace media { @@ -144,8 +143,8 @@ bool EsParserAudio::Parse(const uint8_t* buf, } int64_t current_pts = audio_timestamp_helper_->GetTimestamp(); - int64_t frame_duration = - audio_timestamp_helper_->GetFrameDuration(kSamplesPerAACFrame); + int64_t frame_duration = audio_timestamp_helper_->GetFrameDuration( + audio_header_->GetSamplesPerFrame()); // Emit an audio frame. bool is_key_frame = true; @@ -160,7 +159,7 @@ bool EsParserAudio::Parse(const uint8_t* buf, emit_sample_cb_.Run(pid(), sample); // Update the PTS of the next frame. - audio_timestamp_helper_->AddFrames(kSamplesPerAACFrame); + audio_timestamp_helper_->AddFrames(audio_header_->GetSamplesPerFrame()); // Skip the current frame. es_position += static_cast(audio_header_->GetFrameSize()); diff --git a/packager/media/formats/mp2t/mp2t.gyp b/packager/media/formats/mp2t/mp2t.gyp index 39a2dd28ba..dc069d9ffc 100644 --- a/packager/media/formats/mp2t/mp2t.gyp +++ b/packager/media/formats/mp2t/mp2t.gyp @@ -83,7 +83,6 @@ '../../codecs/codecs.gyp:codecs', '../../event/media_event.gyp:mock_muxer_listener', '../../test/media_test.gyp:media_test_support', - '../mpeg/mpeg.gyp:mpeg', 'mp2t', ] }, diff --git a/packager/media/formats/mpeg/adts_constants.cc b/packager/media/formats/mpeg/adts_constants.cc deleted file mode 100644 index a5c111fb4e..0000000000 --- a/packager/media/formats/mpeg/adts_constants.cc +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "packager/media/formats/mpeg/adts_constants.h" - -#include "packager/base/macros.h" - -namespace shaka { -namespace media { - -// The following conversion table is extracted from ISO 14496 Part 3 - -// Table 1.16 - Sampling Frequency Index. -const int kAdtsFrequencyTable[] = {96000, 88200, 64000, 48000, 44100, - 32000, 24000, 22050, 16000, 12000, - 11025, 8000, 7350}; -const size_t kAdtsFrequencyTableSize = arraysize(kAdtsFrequencyTable); - -// The following conversion table is extracted from ISO 14496 Part 3 - -// Table 1.17 - Channel Configuration. -const int kAdtsNumChannelsTable[] = { - 0, 1, 2, 3, 4, 5, 6, 8 }; -const size_t kAdtsNumChannelsTableSize = arraysize(kAdtsNumChannelsTable); - -} // namespace media -} // namespace shaka diff --git a/packager/media/formats/mpeg/adts_constants.h b/packager/media/formats/mpeg/adts_constants.h deleted file mode 100644 index a929484bc0..0000000000 --- a/packager/media/formats/mpeg/adts_constants.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MEDIA_FORMATS_MPEG_ADTS_CONSTANTS_H_ -#define MEDIA_FORMATS_MPEG_ADTS_CONSTANTS_H_ - -#include - -namespace shaka { -namespace media { - -enum { - kAdtsHeaderMinSize = 7, - kSamplesPerAACFrame = 1024, -}; - -extern const int kAdtsFrequencyTable[]; -extern const size_t kAdtsFrequencyTableSize; - -extern const int kAdtsNumChannelsTable[]; -extern const size_t kAdtsNumChannelsTableSize; - -} // namespace media -} // namespace shaka - -#endif // MEDIA_FORMATS_MPEG_ADTS_CONSTANTS_H_ diff --git a/packager/media/formats/mpeg/mpeg.gyp b/packager/media/formats/mpeg/mpeg.gyp deleted file mode 100644 index 1a0c996baf..0000000000 --- a/packager/media/formats/mpeg/mpeg.gyp +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2014 Google Inc. All rights reserved. -# -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file or at -# https://developers.google.com/open-source/licenses/bsd - -{ - 'includes': [ - '../../../common.gypi', - ], - 'targets': [ - { - 'target_name': 'mpeg', - 'type': '<(component)', - 'sources': [ - 'adts_constants.cc', - 'adts_constants.h', - ], - }, - { - 'target_name': 'mpeg_unittest', - 'type': '<(gtest_target_type)', - 'sources': [ - ], - 'dependencies': [ - '../../../testing/gtest.gyp:gtest', - '../../../testing/gmock.gyp:gmock', - '../../test/media_test.gyp:media_test_support', - 'mpeg', - ] - }, - ], -} diff --git a/packager/media/formats/wvm/wvm.gyp b/packager/media/formats/wvm/wvm.gyp index e6c070071f..530e0ce735 100644 --- a/packager/media/formats/wvm/wvm.gyp +++ b/packager/media/formats/wvm/wvm.gyp @@ -20,7 +20,6 @@ '../../base/media_base.gyp:media_base', '../../codecs/codecs.gyp:codecs', '../../formats/mp2t/mp2t.gyp:mp2t', - '../mpeg/mpeg.gyp:mpeg', ], }, { diff --git a/packager/packager.gyp b/packager/packager.gyp index db1798ba56..8e830b7806 100644 --- a/packager/packager.gyp +++ b/packager/packager.gyp @@ -30,7 +30,6 @@ 'media/event/media_event.gyp:media_event', 'media/formats/mp2t/mp2t.gyp:mp2t', 'media/formats/mp4/mp4.gyp:mp4', - 'media/formats/mpeg/mpeg.gyp:mpeg', 'media/formats/webm/webm.gyp:webm', 'media/formats/webvtt/webvtt.gyp:webvtt', 'media/formats/wvm/wvm.gyp:wvm',