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
This commit is contained in:
KongQun Yang 2018-11-19 16:52:44 -08:00
parent ae3da3772e
commit 4c6059be78
2 changed files with 60 additions and 21 deletions

View File

@ -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 // ATSC Standard A/52:2012 Table 5.18 Frame Size Code Table
// (in words = 16 bits). // (in words = 16 bits).
const size_t kFrameSizeCodeTable[][3] = { const size_t kFrameSizeCodeTable[][3] = {
// {32kHz, 44.1kHz, 48kHz}
{96, 69, 64}, {96, 70, 64}, {120, 87, 80}, {96, 69, 64}, {96, 70, 64}, {120, 87, 80},
{120, 88, 80}, {144, 104, 96}, {144, 105, 96}, {120, 88, 80}, {144, 104, 96}, {144, 105, 96},
{168, 121, 112}, {168, 122, 112}, {192, 139, 128}, {168, 121, 112}, {168, 122, 112}, {192, 139, 128},
@ -103,9 +104,13 @@ size_t Ac3Header::GetHeaderSize() const {
} }
size_t Ac3Header::GetFrameSize() 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)); 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<uint8_t>* buffer) const { void Ac3Header::GetAudioSpecificConfig(std::vector<uint8_t>* buffer) const {

View File

@ -4,15 +4,18 @@
// license that can be found in the LICENSE file or at // license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd // https://developers.google.com/open-source/licenses/bsd
#include <gmock/gmock.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "packager/base/logging.h" #include "packager/base/logging.h"
#include "packager/base/strings/string_number_conversions.h" #include "packager/base/strings/string_number_conversions.h"
#include "packager/media/formats/mp2t/ac3_header.h" #include "packager/media/formats/mp2t/ac3_header.h"
using ::testing::ElementsAreArray;
namespace { namespace {
const char kValidPartialAc3Frame[] = const char kValidPartialAc3Frame44100Hz[] =
"0B772770554043E106F575F080821010415C7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF" "0B772770554043E106F575F080821010415C7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF"
"9F3E7CF9F3EFF9D5F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3" "9F3E7CF9F3EFF9D5F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3"
"E7CF9F3E7CF9F3E7CF9F3E7CF9F3E3FE757CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F" "E7CF9F3E7CF9F3E7CF9F3E7CF9F3E3FE757CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F"
@ -25,6 +28,15 @@ const char kValidPartialAc3Frame[] =
"000000000000000000001DDDDDDE3C78DB6DB6DB6F9F35AD6B5AD6B5AD6B5AD6B5AD6B5AD6" "000000000000000000001DDDDDDE3C78DB6DB6DB6F9F35AD6B5AD6B5AD6B5AD6B5AD6B5AD6"
"9800000000000F1B6DB6DB6DE3C78F1DDD"; "9800000000000F1B6DB6DB6DE3C78F1DDD";
const char kValidPartialAc3Frame48kHz[] =
"0B776068144043E106F46370C0C0C21818187D5C7CF9F3918FA13E7E95F3E8695F427CF9F3"
"F7B09F42A559FA5FF9D5F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7C"
"F9F3E7CF9F3E7CF9F3E3FE757CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7"
"CF9F3E7CF9F3E7CF9F3E7CF8CBFC3122448000000000DF36DB6DB6DB6DBC78F1DDDDDDDDDD"
"DDDDDDDDDDDDDDDDDE3C78DB6DBE7CD6B5AD6B5AD6B5AD6B5AD7236DB964BA92DB246E36DA"
"6D6000000036DB6DB6DB6DB78F1E3BBBBBBBBBBBBBBBBBBBBBBBBBBBC78F1B6DB7CF1AD6B5"
"AD6B5AD6B5AD6A4C000000000006F9B6DB6DB6DB6DE3C78EEEEEEEEEEEEEEEEEEEEE";
const char kValidPartialAc3FrameSixChannels[] = const char kValidPartialAc3FrameSixChannels[] =
"0B77A3B35E40EBF8403EFF9DF0C3F8430FE1FC155755DF3E7CFA33E7CF9F3E7CF9F3E7CF9F" "0B77A3B35E40EBF8403EFF9DF0C3F8430FE1FC155755DF3E7CFA33E7CF9F3E7CF9F3E7CF9F"
"3ECDFF3ABE7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7" "3ECDFF3ABE7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7CF9F3E7"
@ -39,17 +51,21 @@ namespace mp2t {
class Ac3HeaderTest : public testing::Test { class Ac3HeaderTest : public testing::Test {
public: public:
void SetUp() override { 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, ASSERT_TRUE(base::HexStringToBytes(kValidPartialAc3FrameSixChannels,
&ac3_frame_six_channels_)); &ac3_frame_six_channels_));
} }
protected: protected:
std::vector<uint8_t> ac3_frame_; std::vector<uint8_t> ac3_frame_44100_hz_;
std::vector<uint8_t> ac3_frame_48k_hz_;
std::vector<uint8_t> ac3_frame_six_channels_; std::vector<uint8_t> ac3_frame_six_channels_;
}; };
TEST_F(Ac3HeaderTest, ParseSuccess) { TEST_F(Ac3HeaderTest, Parse44100HzSuccess) {
const size_t kExpectedFrameSize(836); const size_t kExpectedFrameSize(836);
const size_t kExpectedHeaderSize(0); const size_t kExpectedHeaderSize(0);
const uint8_t kExpectedObjectType(0); const uint8_t kExpectedObjectType(0);
@ -58,7 +74,8 @@ TEST_F(Ac3HeaderTest, ParseSuccess) {
const uint8_t kExpectedAudioSpecificConfig[] = {0x50, 0x11, 0x40}; const uint8_t kExpectedAudioSpecificConfig[] = {0x50, 0x11, 0x40};
Ac3Header ac3_header; 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(kExpectedFrameSize, ac3_header.GetFrameSize());
EXPECT_EQ(kExpectedHeaderSize, ac3_header.GetHeaderSize()); EXPECT_EQ(kExpectedHeaderSize, ac3_header.GetHeaderSize());
EXPECT_EQ(kExpectedObjectType, ac3_header.GetObjectType()); EXPECT_EQ(kExpectedObjectType, ac3_header.GetObjectType());
@ -66,11 +83,30 @@ TEST_F(Ac3HeaderTest, ParseSuccess) {
EXPECT_EQ(kExpectedNumChannels, ac3_header.GetNumChannels()); EXPECT_EQ(kExpectedNumChannels, ac3_header.GetNumChannels());
std::vector<uint8_t> audio_specific_config; std::vector<uint8_t> audio_specific_config;
ac3_header.GetAudioSpecificConfig(&audio_specific_config); ac3_header.GetAudioSpecificConfig(&audio_specific_config);
EXPECT_EQ(arraysize(kExpectedAudioSpecificConfig), EXPECT_THAT(audio_specific_config,
audio_specific_config.size()); ElementsAreArray(kExpectedAudioSpecificConfig));
EXPECT_EQ(std::vector<uint8_t>(std::begin(kExpectedAudioSpecificConfig), }
std::end(kExpectedAudioSpecificConfig)),
audio_specific_config); 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<uint8_t> audio_specific_config;
ac3_header.GetAudioSpecificConfig(&audio_specific_config);
EXPECT_THAT(audio_specific_config,
ElementsAreArray(kExpectedAudioSpecificConfig));
} }
TEST_F(Ac3HeaderTest, ParseMultiChannelSuccess) { TEST_F(Ac3HeaderTest, ParseMultiChannelSuccess) {
@ -91,28 +127,26 @@ TEST_F(Ac3HeaderTest, ParseMultiChannelSuccess) {
EXPECT_EQ(kExpectedNumChannels, ac3_header.GetNumChannels()); EXPECT_EQ(kExpectedNumChannels, ac3_header.GetNumChannels());
std::vector<uint8_t> audio_specific_config; std::vector<uint8_t> audio_specific_config;
ac3_header.GetAudioSpecificConfig(&audio_specific_config); ac3_header.GetAudioSpecificConfig(&audio_specific_config);
EXPECT_EQ(arraysize(kExpectedAudioSpecificConfig), EXPECT_THAT(audio_specific_config,
audio_specific_config.size()); ElementsAreArray(kExpectedAudioSpecificConfig));
EXPECT_EQ(std::vector<uint8_t>(std::begin(kExpectedAudioSpecificConfig),
std::end(kExpectedAudioSpecificConfig)),
audio_specific_config);
} }
TEST_F(Ac3HeaderTest, ParseVariousDataSize) { TEST_F(Ac3HeaderTest, ParseVariousDataSize) {
Ac3Header ac3_header; Ac3Header ac3_header;
// Parse succeeds as long as the full metadata is provided. // 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 frame_size = ac3_header.GetFrameSize();
const size_t header_size = ac3_header.GetHeaderSize(); 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(frame_size, ac3_header.GetFrameSize());
EXPECT_EQ(header_size, ac3_header.GetHeaderSize()); EXPECT_EQ(header_size, ac3_header.GetHeaderSize());
// Parse fails if there is not enough data (no full metadata). // 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_44100_hz_.data(), 1));
EXPECT_FALSE(ac3_header.Parse(ac3_frame_.data(), 5)); EXPECT_FALSE(ac3_header.Parse(ac3_frame_44100_hz_.data(), 5));
} }
} // Namespace mp2t } // Namespace mp2t