From 4c6059be78d767d2496fc1293eea621c5a31f036 Mon Sep 17 00:00:00 2001 From: KongQun Yang Date: Mon, 19 Nov 2018 16:52:44 -0800 Subject: [PATCH] Fix mpeg-ts demuxing with AC-3/E-AC-3 kFrameSizeCodeTable rows are ordered by 32kHz, 44.1kHz and 48kHz, which is the reverse of fscod (48kHz, 44.1kHz and 32kHz). Also updated unittests. Fixes #487. Change-Id: Icb0afb8bb895afde0028eee05b403bc85bf7b538 --- packager/media/formats/mp2t/ac3_header.cc | 9 ++- .../media/formats/mp2t/ac3_header_unittest.cc | 72 ++++++++++++++----- 2 files changed, 60 insertions(+), 21 deletions(-) diff --git a/packager/media/formats/mp2t/ac3_header.cc b/packager/media/formats/mp2t/ac3_header.cc index 2cf959356e..b12de43aba 100644 --- a/packager/media/formats/mp2t/ac3_header.cc +++ b/packager/media/formats/mp2t/ac3_header.cc @@ -24,6 +24,7 @@ const uint8_t kAc3NumChannelsTable[] = {2, 1, 2, 3, 3, 4, 4, 5}; // ATSC Standard A/52:2012 Table 5.18 Frame Size Code Table // (in words = 16 bits). const size_t kFrameSizeCodeTable[][3] = { + // {32kHz, 44.1kHz, 48kHz} {96, 69, 64}, {96, 70, 64}, {120, 87, 80}, {120, 88, 80}, {144, 104, 96}, {144, 105, 96}, {168, 121, 112}, {168, 122, 112}, {192, 139, 128}, @@ -103,9 +104,13 @@ size_t Ac3Header::GetHeaderSize() const { } size_t Ac3Header::GetFrameSize() const { - DCHECK_LT(fscod_, arraysize(kAc3SampleRateTable)); + const size_t kNumFscode = arraysize(kAc3SampleRateTable); + DCHECK_LT(fscod_, kNumFscode); DCHECK_LT(frmsizecod_, arraysize(kFrameSizeCodeTable)); - return kFrameSizeCodeTable[frmsizecod_][fscod_] * 2; + // The order of frequencies are reversed in |kFrameSizeCodeTable| compared to + // |kAc3SampleRateTable|. + const int index = kNumFscode - 1 - fscod_; + return kFrameSizeCodeTable[frmsizecod_][index] * 2; } void Ac3Header::GetAudioSpecificConfig(std::vector* buffer) const { diff --git a/packager/media/formats/mp2t/ac3_header_unittest.cc b/packager/media/formats/mp2t/ac3_header_unittest.cc index ade3c4acc3..753b8c76df 100644 --- a/packager/media/formats/mp2t/ac3_header_unittest.cc +++ b/packager/media/formats/mp2t/ac3_header_unittest.cc @@ -4,15 +4,18 @@ // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd +#include #include #include "packager/base/logging.h" #include "packager/base/strings/string_number_conversions.h" #include "packager/media/formats/mp2t/ac3_header.h" +using ::testing::ElementsAreArray; + namespace { -const char kValidPartialAc3Frame[] = +const char kValidPartialAc3Frame44100Hz[] = "0B772770554043E106F575F080821010415C7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF" "9F3E7CF9F3EFF9D5F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3" "E7CF9F3E7CF9F3E7CF9F3E7CF9F3E3FE757CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F" @@ -25,6 +28,15 @@ const char kValidPartialAc3Frame[] = "000000000000000000001DDDDDDE3C78DB6DB6DB6F9F35AD6B5AD6B5AD6B5AD6B5AD6B5AD6" "9800000000000F1B6DB6DB6DE3C78F1DDD"; +const char kValidPartialAc3Frame48kHz[] = + "0B776068144043E106F46370C0C0C21818187D5C7CF9F3918FA13E7E95F3E8695F427CF9F3" + "F7B09F42A559FA5FF9D5F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7C" + "F9F3E7CF9F3E7CF9F3E3FE757CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7" + "CF9F3E7CF9F3E7CF9F3E7CF8CBFC3122448000000000DF36DB6DB6DB6DBC78F1DDDDDDDDDD" + "DDDDDDDDDDDDDDDDDE3C78DB6DBE7CD6B5AD6B5AD6B5AD6B5AD7236DB964BA92DB246E36DA" + "6D6000000036DB6DB6DB6DB78F1E3BBBBBBBBBBBBBBBBBBBBBBBBBBBC78F1B6DB7CF1AD6B5" + "AD6B5AD6B5AD6A4C000000000006F9B6DB6DB6DB6DE3C78EEEEEEEEEEEEEEEEEEEEE"; + const char kValidPartialAc3FrameSixChannels[] = "0B77A3B35E40EBF8403EFF9DF0C3F8430FE1FC155755DF3E7CFA33E7CF9F3E7CF9F3E7CF9F" "3ECDFF3ABE7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7" @@ -39,17 +51,21 @@ namespace mp2t { class Ac3HeaderTest : public testing::Test { public: void SetUp() override { - ASSERT_TRUE(base::HexStringToBytes(kValidPartialAc3Frame, &ac3_frame_)); + ASSERT_TRUE(base::HexStringToBytes(kValidPartialAc3Frame44100Hz, + &ac3_frame_44100_hz_)); + ASSERT_TRUE( + base::HexStringToBytes(kValidPartialAc3Frame48kHz, &ac3_frame_48k_hz_)); ASSERT_TRUE(base::HexStringToBytes(kValidPartialAc3FrameSixChannels, &ac3_frame_six_channels_)); } protected: - std::vector ac3_frame_; + std::vector ac3_frame_44100_hz_; + std::vector ac3_frame_48k_hz_; std::vector ac3_frame_six_channels_; }; -TEST_F(Ac3HeaderTest, ParseSuccess) { +TEST_F(Ac3HeaderTest, Parse44100HzSuccess) { const size_t kExpectedFrameSize(836); const size_t kExpectedHeaderSize(0); const uint8_t kExpectedObjectType(0); @@ -58,7 +74,8 @@ TEST_F(Ac3HeaderTest, ParseSuccess) { const uint8_t kExpectedAudioSpecificConfig[] = {0x50, 0x11, 0x40}; Ac3Header ac3_header; - ASSERT_TRUE(ac3_header.Parse(ac3_frame_.data(), ac3_frame_.size())); + ASSERT_TRUE( + ac3_header.Parse(ac3_frame_44100_hz_.data(), ac3_frame_44100_hz_.size())); EXPECT_EQ(kExpectedFrameSize, ac3_header.GetFrameSize()); EXPECT_EQ(kExpectedHeaderSize, ac3_header.GetHeaderSize()); EXPECT_EQ(kExpectedObjectType, ac3_header.GetObjectType()); @@ -66,11 +83,30 @@ TEST_F(Ac3HeaderTest, ParseSuccess) { 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); + EXPECT_THAT(audio_specific_config, + ElementsAreArray(kExpectedAudioSpecificConfig)); +} + +TEST_F(Ac3HeaderTest, Parse48kHzSuccess) { + const size_t kExpectedFrameSize(768); + const size_t kExpectedHeaderSize(0); + const uint8_t kExpectedObjectType(0); + const uint32_t kExpectedSamplingFrequency(48000); + const uint8_t kExpectedNumChannels(2); + const uint8_t kExpectedAudioSpecificConfig[] = {0x10, 0x11, 0x40}; + + Ac3Header ac3_header; + ASSERT_TRUE( + ac3_header.Parse(ac3_frame_48k_hz_.data(), ac3_frame_48k_hz_.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_THAT(audio_specific_config, + ElementsAreArray(kExpectedAudioSpecificConfig)); } TEST_F(Ac3HeaderTest, ParseMultiChannelSuccess) { @@ -91,28 +127,26 @@ TEST_F(Ac3HeaderTest, ParseMultiChannelSuccess) { 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); + EXPECT_THAT(audio_specific_config, + ElementsAreArray(kExpectedAudioSpecificConfig)); } TEST_F(Ac3HeaderTest, ParseVariousDataSize) { Ac3Header ac3_header; // Parse succeeds as long as the full metadata is provided. - EXPECT_TRUE(ac3_header.Parse(ac3_frame_.data(), ac3_frame_.size() - 1)); + EXPECT_TRUE(ac3_header.Parse(ac3_frame_44100_hz_.data(), + ac3_frame_44100_hz_.size() - 1)); const size_t frame_size = ac3_header.GetFrameSize(); const size_t header_size = ac3_header.GetHeaderSize(); - EXPECT_TRUE(ac3_header.Parse(ac3_frame_.data(), 100)); + EXPECT_TRUE(ac3_header.Parse(ac3_frame_44100_hz_.data(), 100)); EXPECT_EQ(frame_size, ac3_header.GetFrameSize()); EXPECT_EQ(header_size, ac3_header.GetHeaderSize()); // Parse fails if there is not enough data (no full metadata). - EXPECT_FALSE(ac3_header.Parse(ac3_frame_.data(), 1)); - EXPECT_FALSE(ac3_header.Parse(ac3_frame_.data(), 5)); + EXPECT_FALSE(ac3_header.Parse(ac3_frame_44100_hz_.data(), 1)); + EXPECT_FALSE(ac3_header.Parse(ac3_frame_44100_hz_.data(), 5)); } } // Namespace mp2t