diff options
Diffstat (limited to 'media/mp4')
-rw-r--r-- | media/mp4/aac.cc | 252 | ||||
-rw-r--r-- | media/mp4/aac.h | 67 | ||||
-rw-r--r-- | media/mp4/aac_unittest.cc | 104 | ||||
-rw-r--r-- | media/mp4/avc.cc | 22 | ||||
-rw-r--r-- | media/mp4/avc.h | 4 | ||||
-rw-r--r-- | media/mp4/box_definitions.cc | 28 | ||||
-rw-r--r-- | media/mp4/box_definitions.h | 9 | ||||
-rw-r--r-- | media/mp4/es_descriptor.cc | 112 | ||||
-rw-r--r-- | media/mp4/es_descriptor.h | 57 | ||||
-rw-r--r-- | media/mp4/es_descriptor_unittest.cc | 92 | ||||
-rw-r--r-- | media/mp4/mp4_stream_parser.cc | 16 | ||||
-rw-r--r-- | media/mp4/mp4_stream_parser.h | 4 |
12 files changed, 734 insertions, 33 deletions
diff --git a/media/mp4/aac.cc b/media/mp4/aac.cc new file mode 100644 index 0000000..e79e927 --- /dev/null +++ b/media/mp4/aac.cc @@ -0,0 +1,252 @@ +// Copyright (c) 2012 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 "media/mp4/aac.h" + +#include "base/logging.h" +#include "media/base/bit_reader.h" +#include "media/mp4/rcheck.h" + +// The following conversion table is extracted from ISO 14496 Part 3 - +// Table 1.16 - Sampling Frequency Index. +static const uint32 kFrequencyMap[] = { + 96000, 88200, 64000, 48000, 44100, 32000, 24000, + 22050, 16000, 12000, 11025, 8000, 7350 +}; + +static ChannelLayout GetChannelLayout(uint8 channel_config) { + switch (channel_config) { + case 1: + return CHANNEL_LAYOUT_MONO; + case 2: + return CHANNEL_LAYOUT_STEREO; + case 3: + return CHANNEL_LAYOUT_SURROUND; + case 4: + return CHANNEL_LAYOUT_4_0; + case 5: + return CHANNEL_LAYOUT_5_0; + case 6: + return CHANNEL_LAYOUT_5_1; + case 8: + return CHANNEL_LAYOUT_7_1; + default: + break; + } + + return CHANNEL_LAYOUT_UNSUPPORTED; +} + +namespace media { + +namespace mp4 { + +AAC::AAC() + : profile_(0), frequency_index_(0), channel_config_(0), frequency_(0), + channel_layout_(CHANNEL_LAYOUT_UNSUPPORTED) { +} + +AAC::~AAC() { +} + +bool AAC::Parse(const std::vector<uint8>& data) { + BitReader reader; + uint8 extension_type = 0; + bool ps_present = false; + uint8 extension_frequency_index; + + profile_ = 0; + frequency_index_ = 0; + frequency_ = 0; + channel_config_ = 0; + + reader.Initialize(&data[0], data.size()); + + // The following code is written according to ISO 14496 Part 3 Table 1.13 - + // Syntax of AudioSpecificConfig. + + // Read base configuration + RCHECK(reader.ReadBits(5, &profile_)); + RCHECK(reader.ReadBits(4, &frequency_index_)); + if (frequency_index_ == 0xf) + RCHECK(reader.ReadBits(24, &frequency_)); + RCHECK(reader.ReadBits(4, &channel_config_)); + + extension_frequency_index = frequency_index_; + + // Read extension configuration + if (profile_ == 5 || profile_ == 29) { + ps_present = (profile_ == 29); + extension_type = 5; + RCHECK(reader.ReadBits(4, &extension_frequency_index)); + if (extension_frequency_index == 0xf) + RCHECK(reader.ReadBits(24, &frequency_)); + RCHECK(reader.ReadBits(5, &profile_)); + } + + RCHECK(SkipDecoderGASpecificConfig(&reader)); + RCHECK(SkipErrorSpecificConfig()); + + // Read extension configuration again + if (extension_type != 5 && reader.NumBitsLeft() >= 16) { + uint16 sync_extension_type; + uint8 sbr_present_flag; + uint8 ps_present_flag; + + RCHECK(reader.ReadBits(11, &sync_extension_type)); + + if (sync_extension_type == 0x2b7) { + RCHECK(reader.ReadBits(5, &extension_type)); + + if (extension_type == 5) { + RCHECK(reader.ReadBits(1, &sbr_present_flag)); + + if (sbr_present_flag) { + RCHECK(reader.ReadBits(4, &extension_frequency_index)); + + if (extension_frequency_index == 0xf) + RCHECK(reader.ReadBits(24, &frequency_)); + + RCHECK(reader.ReadBits(11, &sync_extension_type)); + + if (sync_extension_type == 0x548) { + RCHECK(reader.ReadBits(1, &ps_present_flag)); + ps_present = ps_present_flag != 0; + } + } + } + } + } + + if (frequency_ == 0) { + RCHECK(extension_frequency_index < arraysize(kFrequencyMap)); + frequency_ = kFrequencyMap[extension_frequency_index]; + } + + // When Parametric Stereo is on, mono will be played as stereo. + if (ps_present && channel_config_ == 1) + channel_layout_ = GetChannelLayout(channel_config_ + 1); + else + channel_layout_ = GetChannelLayout(channel_config_); + + return frequency_ != 0 && channel_layout_ != CHANNEL_LAYOUT_UNSUPPORTED && + profile_ >= 1 && profile_ <= 4 && frequency_index_ != 0xf && + channel_config_ <= 7; +} + +uint32 AAC::frequency() const { + return frequency_; +} + +ChannelLayout AAC::channel_layout() const { + return channel_layout_; +} + +bool AAC::ConvertEsdsToADTS(std::vector<uint8>* buffer) const { + size_t size = buffer->size() + 7; + + DCHECK(profile_ >= 1 && profile_ <= 4 && frequency_index_ != 0xf && + channel_config_ <= 7); + + // ADTS header uses 13 bits for packet size. + if (size > (1 << 13) - 1) + return false; + + std::vector<uint8>& adts = *buffer; + + adts.insert(buffer->begin(), 7, 0); + adts[0] = 0xff; + adts[1] = 0xf1; + adts[2] = ((profile_ - 1) << 6) + (frequency_index_ << 2) + + (channel_config_ >> 2); + adts[3] = ((channel_config_ & 0x3) << 6) + (size >> 11); + adts[4] = (size & 0x7ff) >> 3; + adts[5] = ((size & 7) << 5) + 0x1f; + adts[6] = 0xfc; + + return true; +} + +// Currently this function only support GASpecificConfig defined in +// ISO 14496 Part 3 Table 4.1 - Syntax of GASpecificConfig() +bool AAC::SkipDecoderGASpecificConfig(BitReader* bit_reader) const { + switch (profile_) { + case 1: + case 2: + case 3: + case 4: + case 6: + case 7: + case 17: + case 19: + case 20: + case 21: + case 22: + case 23: + return SkipGASpecificConfig(bit_reader); + default: + break; + } + + return false; +} + +bool AAC::SkipErrorSpecificConfig() const { + switch (profile_) { + case 17: + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 27: + return false; + default: + break; + } + + return true; +} + +// The following code is written according to ISO 14496 part 3 Table 4.1 - +// GASpecificConfig. +bool AAC::SkipGASpecificConfig(BitReader* bit_reader) const { + uint8 extension_flag = 0; + uint8 depends_on_core_coder; + + RCHECK(bit_reader->SkipBits(1)); // frameLengthFlag + RCHECK(bit_reader->ReadBits(1, &depends_on_core_coder)); + if (depends_on_core_coder == 1) + RCHECK(bit_reader->SkipBits(14)); // coreCoderDelay + + RCHECK(bit_reader->ReadBits(1, &extension_flag)); + RCHECK(channel_config_ != 0); + + if (profile_ == 6 || profile_ == 20) + RCHECK(bit_reader->SkipBits(3)); + + if (extension_flag) { + if (profile_ == 22) { + RCHECK(bit_reader->SkipBits(5)); + RCHECK(bit_reader->SkipBits(11)); + } + + if (profile_ == 17 || profile_ == 19 || profile_ == 20 || profile_ == 23) { + RCHECK(bit_reader->SkipBits(1)); + RCHECK(bit_reader->SkipBits(1)); + RCHECK(bit_reader->SkipBits(1)); + } + + RCHECK(bit_reader->SkipBits(1)); + } + + return true; +} + +} // namespace mp4 + +} // namespace media diff --git a/media/mp4/aac.h b/media/mp4/aac.h new file mode 100644 index 0000000..7a2a3f8 --- /dev/null +++ b/media/mp4/aac.h @@ -0,0 +1,67 @@ +// Copyright (c) 2012 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_MP4_AAC_H_ +#define MEDIA_MP4_AAC_H_ + +#include <vector> + +#include "base/basictypes.h" +#include "media/base/channel_layout.h" +#include "media/base/media_export.h" + +namespace media { + +class BitReader; + +namespace mp4 { + +// This class parses the AAC information from decoder specific information +// embedded in the esds box in an ISO BMFF file. +// Please refer to ISO 14496 Part 3 Table 1.13 - Syntax of AudioSpecificConfig +// for more details. +class MEDIA_EXPORT AAC { + public: + AAC(); + ~AAC(); + + // Parse the AAC config from the raw binary data embedded in esds box. + // The function will parse the data and get the ElementaryStreamDescriptor, + // then it will parse the ElementaryStreamDescriptor to get audio stream + // configurations. + bool Parse(const std::vector<uint8>& data); + + uint32 frequency() const; + ChannelLayout channel_layout() const; + + // This function converts a raw AAC frame into an AAC frame with an ADTS + // header. On success, the function returns true and stores the converted data + // in the buffer. The function returns false on failure and leaves the buffer + // unchanged. + bool ConvertEsdsToADTS(std::vector<uint8>* buffer) const; + + private: + bool SkipDecoderGASpecificConfig(BitReader* bit_reader) const; + bool SkipErrorSpecificConfig() const; + bool SkipGASpecificConfig(BitReader* bit_reader) const; + + // The following variables store the AAC specific configuration information + // that are used to generate the ADTS header. + uint8 profile_; + uint8 frequency_index_; + uint8 channel_config_; + + // The following variables store audio configuration information that + // can be used by Chromium. They are based on the AAC specific + // configuration but can be overridden by extensions in elementary + // stream descriptor. + uint32 frequency_; + ChannelLayout channel_layout_; +}; + +} // namespace mp4 + +} // namespace media + +#endif // MEDIA_MP4_AAC_H_ diff --git a/media/mp4/aac_unittest.cc b/media/mp4/aac_unittest.cc new file mode 100644 index 0000000..2f61de5 --- /dev/null +++ b/media/mp4/aac_unittest.cc @@ -0,0 +1,104 @@ +// Copyright (c) 2012 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 "media/mp4/aac.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace media { + +namespace mp4 { + +TEST(AACTest, BasicProfileTest) { + AAC aac; + uint8 buffer[] = {0x12, 0x10}; + std::vector<uint8> data; + + data.assign(buffer, buffer + sizeof(buffer)); + + EXPECT_TRUE(aac.Parse(data)); + EXPECT_EQ(aac.frequency(), 44100u); + EXPECT_EQ(aac.channel_layout(), CHANNEL_LAYOUT_STEREO); +} + +TEST(AACTest, ExtensionTest) { + AAC aac; + uint8 buffer[] = {0x13, 0x08, 0x56, 0xe5, 0x9d, 0x48, 0x80}; + std::vector<uint8> data; + + data.assign(buffer, buffer + sizeof(buffer)); + + EXPECT_TRUE(aac.Parse(data)); + EXPECT_EQ(aac.frequency(), 48000u); + EXPECT_EQ(aac.channel_layout(), CHANNEL_LAYOUT_STEREO); +} + +TEST(AACTest, SixChannelTest) { + AAC aac; + uint8 buffer[] = {0x11, 0xb0}; + std::vector<uint8> data; + + data.assign(buffer, buffer + sizeof(buffer)); + + EXPECT_TRUE(aac.Parse(data)); + EXPECT_EQ(aac.frequency(), 48000u); + EXPECT_EQ(aac.channel_layout(), CHANNEL_LAYOUT_5_1); +} + +TEST(AACTest, DataTooShortTest) { + AAC aac; + std::vector<uint8> data; + + EXPECT_FALSE(aac.Parse(data)); + + data.push_back(0x12); + EXPECT_FALSE(aac.Parse(data)); +} + +TEST(AACTest, IncorrectProfileTest) { + AAC aac; + uint8 buffer[] = {0x0, 0x08}; + std::vector<uint8> data; + + data.assign(buffer, buffer + sizeof(buffer)); + + EXPECT_FALSE(aac.Parse(data)); + + data[0] = 0x08; + EXPECT_TRUE(aac.Parse(data)); + + data[0] = 0x28; + EXPECT_FALSE(aac.Parse(data)); +} + +TEST(AACTest, IncorrectFrequencyTest) { + AAC aac; + uint8 buffer[] = {0x0f, 0x88}; + std::vector<uint8> data; + + data.assign(buffer, buffer + sizeof(buffer)); + + EXPECT_FALSE(aac.Parse(data)); + + data[0] = 0x0e; + data[1] = 0x08; + EXPECT_TRUE(aac.Parse(data)); +} + +TEST(AACTest, IncorrectChannelTest) { + AAC aac; + uint8 buffer[] = {0x0e, 0x00}; + std::vector<uint8> data; + + data.assign(buffer, buffer + sizeof(buffer)); + + EXPECT_FALSE(aac.Parse(data)); + + data[1] = 0x08; + EXPECT_TRUE(aac.Parse(data)); +} + +} // namespace mp4 + +} // namespace media diff --git a/media/mp4/avc.cc b/media/mp4/avc.cc index faf9939..2999466 100644 --- a/media/mp4/avc.cc +++ b/media/mp4/avc.cc @@ -88,27 +88,5 @@ bool AVC::InsertParameterSets(const AVCDecoderConfigurationRecord& avc_config, return true; } -// static -ChannelLayout AVC::ConvertAACChannelCountToChannelLayout(int count) { - switch (count) { - case 1: - return CHANNEL_LAYOUT_MONO; - case 2: - return CHANNEL_LAYOUT_STEREO; - case 3: - return CHANNEL_LAYOUT_SURROUND; - case 4: - return CHANNEL_LAYOUT_4_0; - case 5: - return CHANNEL_LAYOUT_5_0; - case 6: - return CHANNEL_LAYOUT_5_1; - case 8: - return CHANNEL_LAYOUT_7_1; - default: - return CHANNEL_LAYOUT_UNSUPPORTED; - } -} - } // namespace mp4 } // namespace media diff --git a/media/mp4/avc.h b/media/mp4/avc.h index 2767c14..8e826b0 100644 --- a/media/mp4/avc.h +++ b/media/mp4/avc.h @@ -8,7 +8,6 @@ #include <vector> #include "base/basictypes.h" -#include "media/base/channel_layout.h" #include "media/base/media_export.h" namespace media { @@ -23,11 +22,8 @@ class MEDIA_EXPORT AVC { static bool InsertParameterSets( const AVCDecoderConfigurationRecord& avc_config, std::vector<uint8>* buffer); - - static ChannelLayout ConvertAACChannelCountToChannelLayout(int count); }; - } // namespace mp4 } // namespace media diff --git a/media/mp4/box_definitions.cc b/media/mp4/box_definitions.cc index ff86372..eb43530 100644 --- a/media/mp4/box_definitions.cc +++ b/media/mp4/box_definitions.cc @@ -5,8 +5,7 @@ #include "media/mp4/box_definitions.h" #include "base/logging.h" -#include "media/mp4/box_reader.h" -#include "media/mp4/fourccs.h" +#include "media/mp4/es_descriptor.h" #include "media/mp4/rcheck.h" namespace media { @@ -389,6 +388,29 @@ bool VideoSampleEntry::Parse(BoxReader* reader) { return true; } +ElementaryStreamDescriptor::ElementaryStreamDescriptor() {} + +ElementaryStreamDescriptor::~ElementaryStreamDescriptor() {} + +FourCC ElementaryStreamDescriptor::BoxType() const { + return FOURCC_ESDS; +} + +bool ElementaryStreamDescriptor::Parse(BoxReader* reader) { + std::vector<uint8> data; + ESDescriptor es_desc; + + RCHECK(reader->ReadFullBoxHeader()); + RCHECK(reader->ReadVec(&data, reader->size() - reader->pos())); + RCHECK(es_desc.Parse(data)); + + object_type = es_desc.object_type(); + + RCHECK(aac.Parse(es_desc.decoder_specific_info())); + + return true; +} + AudioSampleEntry::AudioSampleEntry() : format(FOURCC_NULL), data_reference_index(0), @@ -397,6 +419,7 @@ AudioSampleEntry::AudioSampleEntry() samplerate(0) {} AudioSampleEntry::~AudioSampleEntry() {} + FourCC AudioSampleEntry::BoxType() const { DCHECK(false) << "AudioSampleEntry should be parsed according to the " << "handler type recovered in its Media ancestor."; @@ -419,6 +442,7 @@ bool AudioSampleEntry::Parse(BoxReader* reader) { if (format == FOURCC_ENCA) { RCHECK(reader->ReadChild(&sinf)); } + RCHECK(reader->ReadChild(&esds)); return true; } diff --git a/media/mp4/box_definitions.h b/media/mp4/box_definitions.h index 52a0e86..0b7e771 100644 --- a/media/mp4/box_definitions.h +++ b/media/mp4/box_definitions.h @@ -11,6 +11,7 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" #include "media/base/media_export.h" +#include "media/mp4/aac.h" #include "media/mp4/avc.h" #include "media/mp4/box_reader.h" #include "media/mp4/fourccs.h" @@ -184,6 +185,13 @@ struct VideoSampleEntry : Box { AVCDecoderConfigurationRecord avcc; }; +struct ElementaryStreamDescriptor : Box { + DECLARE_BOX_METHODS(ElementaryStreamDescriptor); + + uint8 object_type; + AAC aac; +}; + struct AudioSampleEntry : Box { DECLARE_BOX_METHODS(AudioSampleEntry); @@ -194,6 +202,7 @@ struct AudioSampleEntry : Box { uint32 samplerate; ProtectionSchemeInfo sinf; + ElementaryStreamDescriptor esds; }; struct SampleDescription : Box { diff --git a/media/mp4/es_descriptor.cc b/media/mp4/es_descriptor.cc new file mode 100644 index 0000000..1cb4c65 --- /dev/null +++ b/media/mp4/es_descriptor.cc @@ -0,0 +1,112 @@ +// Copyright (c) 2012 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 "media/mp4/es_descriptor.h" + +#include "media/base/bit_reader.h" +#include "media/mp4/rcheck.h" + +// The elementary stream size is specific by up to 4 bytes. +// The MSB of a byte indicates if there are more bytes for the size. +static bool ReadESSize(media::BitReader* reader, uint32* size) { + uint8 msb; + uint8 byte; + + *size = 0; + + for (size_t i = 0; i < 4; ++i) { + RCHECK(reader->ReadBits(1, &msb)); + RCHECK(reader->ReadBits(7, &byte)); + *size = (*size << 7) + byte; + + if (msb == 0) + break; + } + + return true; +} + +namespace media { + +namespace mp4 { + +ESDescriptor::ESDescriptor() + : object_type_(kForbidden) { +} + +ESDescriptor::~ESDescriptor() {} + +bool ESDescriptor::Parse(const std::vector<uint8>& data) { + BitReader reader(&data[0], data.size()); + uint8 tag; + uint32 size; + uint8 stream_dependency_flag; + uint8 url_flag; + uint8 ocr_stream_flag; + + RCHECK(reader.ReadBits(8, &tag)); + RCHECK(tag == kESDescrTag); + RCHECK(ReadESSize(&reader, &size)); + RCHECK(static_cast<off_t>(size * CHAR_BIT) <= reader.NumBitsLeft()); + + RCHECK(reader.SkipBits(16)); // ES_ID + RCHECK(reader.ReadBits(1, &stream_dependency_flag)); + RCHECK(reader.ReadBits(1, &url_flag)); + RCHECK(reader.ReadBits(1, &ocr_stream_flag)); + RCHECK(reader.SkipBits(5)); // streamPriority + + if (stream_dependency_flag) + reader.SkipBits(16); // dependsOn_ES_ID; + RCHECK(!url_flag); // We don't support url flag + if (ocr_stream_flag) + reader.SkipBits(16); // OCR_ES_Id + + RCHECK(ParseDecoderConfigDescriptor(&reader)); + + return true; +} + +uint8 ESDescriptor::object_type() const { + return object_type_; +} + +const std::vector<uint8>& ESDescriptor::decoder_specific_info() const { + return decoder_specific_info_; +} + +bool ESDescriptor::ParseDecoderConfigDescriptor(BitReader* reader) { + uint8 tag; + uint32 size; + + RCHECK(reader->ReadBits(8, &tag)); + RCHECK(tag == kDecoderConfigDescrTag); + RCHECK(ReadESSize(reader, &size)); + RCHECK(static_cast<off_t>(size * CHAR_BIT) <= reader->NumBitsLeft()); + + RCHECK(reader->ReadBits(8, &object_type_)); + RCHECK(reader->SkipBits(96)); + RCHECK(ParseDecoderSpecificInfo(reader)); + + return true; +} + +bool ESDescriptor::ParseDecoderSpecificInfo(BitReader* reader) { + uint8 tag; + uint32 size; + + RCHECK(reader->ReadBits(8, &tag)); + RCHECK(tag == kDecoderSpecificInfoTag); + RCHECK(ReadESSize(reader, &size)); + RCHECK(static_cast<off_t>(size * CHAR_BIT) <= reader->NumBitsLeft()); + + decoder_specific_info_.resize(size); + for (uint32 i = 0; i < size; ++i) + RCHECK(reader->ReadBits(8, &decoder_specific_info_[i])); + + return true; +} + +} // namespace mp4 + +} // namespace media diff --git a/media/mp4/es_descriptor.h b/media/mp4/es_descriptor.h new file mode 100644 index 0000000..daddbc0 --- /dev/null +++ b/media/mp4/es_descriptor.h @@ -0,0 +1,57 @@ +// Copyright (c) 2012 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_MP4_ES_DESCRIPTOR_H_ +#define MEDIA_MP4_ES_DESCRIPTOR_H_ + +#include <vector> + +#include "base/basictypes.h" +#include "media/base/media_export.h" + +namespace media { + +class BitReader; + +namespace mp4 { + +// The following values are extracted from ISO 14496 Part 1 Table 5 - +// objectTypeIndication Values. Only values currently in use are included. +enum ObjectType { + kForbidden = 0, + kISO_14496_3 = 0x40 // MPEG4 AAC +}; + +// This class parse object type and decoder specific information from an +// elementary stream descriptor, which is usually contained in an esds box. +// Please refer to ISO 14496 Part 1 7.2.6.5 for more details. +class MEDIA_EXPORT ESDescriptor { + public: + ESDescriptor(); + ~ESDescriptor(); + + bool Parse(const std::vector<uint8>& data); + + uint8 object_type() const; + const std::vector<uint8>& decoder_specific_info() const; + + private: + enum Tag { + kESDescrTag = 0x03, + kDecoderConfigDescrTag = 0x04, + kDecoderSpecificInfoTag = 0x05 + }; + + bool ParseDecoderConfigDescriptor(BitReader* reader); + bool ParseDecoderSpecificInfo(BitReader* reader); + + uint8 object_type_; + std::vector<uint8> decoder_specific_info_; +}; + +} // namespace mp4 + +} // namespace media + +#endif // MEDIA_MP4_ES_DESCRIPTOR_H_ diff --git a/media/mp4/es_descriptor_unittest.cc b/media/mp4/es_descriptor_unittest.cc new file mode 100644 index 0000000..c3a39fb --- /dev/null +++ b/media/mp4/es_descriptor_unittest.cc @@ -0,0 +1,92 @@ +// Copyright (c) 2012 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 "media/mp4/es_descriptor.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace media { + +namespace mp4 { + +TEST(ESDescriptorTest, SingleByteLengthTest) { + ESDescriptor es_desc; + uint8 buffer[] = { + 0x03, 0x19, 0x00, 0x01, 0x00, 0x04, 0x11, 0x40, + 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x02, 0x12, 0x10, + 0x06, 0x01, 0x02 + }; + std::vector<uint8> data; + + data.assign(buffer, buffer + sizeof(buffer)); + + EXPECT_EQ(es_desc.object_type(), kForbidden); + EXPECT_TRUE(es_desc.Parse(data)); + EXPECT_EQ(es_desc.object_type(), kISO_14496_3); + EXPECT_EQ(es_desc.decoder_specific_info().size(), 2u); + EXPECT_EQ(es_desc.decoder_specific_info()[0], 0x12); + EXPECT_EQ(es_desc.decoder_specific_info()[1], 0x10); +} + +TEST(ESDescriptorTest, NonAACTest) { + ESDescriptor es_desc; + uint8 buffer[] = { + 0x03, 0x19, 0x00, 0x01, 0x00, 0x04, 0x11, 0x66, + 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x02, 0x12, 0x10, + 0x06, 0x01, 0x02 + }; + std::vector<uint8> data; + + data.assign(buffer, buffer + sizeof(buffer)); + + EXPECT_TRUE(es_desc.Parse(data)); + EXPECT_NE(es_desc.object_type(), kISO_14496_3); + EXPECT_EQ(es_desc.decoder_specific_info().size(), 2u); + EXPECT_EQ(es_desc.decoder_specific_info()[0], 0x12); + EXPECT_EQ(es_desc.decoder_specific_info()[1], 0x10); +} + +TEST(ESDescriptorTest, MultiByteLengthTest) { + ESDescriptor es_desc; + uint8 buffer[] = { + 0x03, 0x80, 0x19, 0x00, 0x01, 0x00, 0x04, 0x80, + 0x80, 0x11, 0x40, 0x15, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, + 0x80, 0x80, 0x80, 0x02, 0x12, 0x10, 0x06, 0x01, + 0x02 + }; + std::vector<uint8> data; + + data.assign(buffer, buffer + sizeof(buffer)); + + EXPECT_TRUE(es_desc.Parse(data)); + EXPECT_EQ(es_desc.object_type(), kISO_14496_3); + EXPECT_EQ(es_desc.decoder_specific_info().size(), 2u); + EXPECT_EQ(es_desc.decoder_specific_info()[0], 0x12); + EXPECT_EQ(es_desc.decoder_specific_info()[1], 0x10); +} + +TEST(ESDescriptorTest, FiveByteLengthTest) { + ESDescriptor es_desc; + uint8 buffer[] = { + 0x03, 0x80, 0x19, 0x00, 0x01, 0x00, 0x04, 0x80, + 0x80, 0x11, 0x40, 0x15, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, + 0x80, 0x80, 0x80, 0x80, 0x02, 0x12, 0x10, 0x06, + 0x01, 0x02 + }; + std::vector<uint8> data; + + data.assign(buffer, buffer + sizeof(buffer)); + + EXPECT_TRUE(es_desc.Parse(data)); + EXPECT_EQ(es_desc.object_type(), kISO_14496_3); + EXPECT_EQ(es_desc.decoder_specific_info().size(), 0u); +} + +} // namespace mp4 + +} // namespace media diff --git a/media/mp4/mp4_stream_parser.cc b/media/mp4/mp4_stream_parser.cc index bb2a95c..ebaa2a2 100644 --- a/media/mp4/mp4_stream_parser.cc +++ b/media/mp4/mp4_stream_parser.cc @@ -13,6 +13,7 @@ #include "media/base/video_decoder_config.h" #include "media/mp4/box_definitions.h" #include "media/mp4/box_reader.h" +#include "media/mp4/es_descriptor.h" #include "media/mp4/rcheck.h" namespace media { @@ -162,10 +163,13 @@ bool MP4StreamParser::ParseMoov(BoxReader* reader) { // (entry.format == FOURCC_ENCA && // entry.sinf.format.format == FOURCC_MP4A)); - const ChannelLayout layout = - AVC::ConvertAACChannelCountToChannelLayout(entry.channelcount); - audio_config.Initialize(kCodecAAC, entry.samplesize, layout, - entry.samplerate, NULL, 0, false); + // Check if it is MPEG4 AAC defined in ISO 14496 Part 3. + RCHECK(entry.esds.object_type == kISO_14496_3); + aac_ = entry.esds.aac; + audio_config.Initialize(kCodecAAC, entry.samplesize, + aac_.channel_layout(), aac_.frequency(), + NULL, 0, false); + has_audio_ = true; audio_track_id_ = track->header.track_id; } @@ -291,6 +295,10 @@ bool MP4StreamParser::EnqueueSample(BufferQueue* audio_buffers, } } + if (audio) { + aac_.ConvertEsdsToADTS(&frame_buf); + } + scoped_refptr<StreamParserBuffer> stream_buf = StreamParserBuffer::CopyFrom(&frame_buf[0], frame_buf.size(), runs_.is_keyframe()); diff --git a/media/mp4/mp4_stream_parser.h b/media/mp4/mp4_stream_parser.h index 7d9be27..706aa65 100644 --- a/media/mp4/mp4_stream_parser.h +++ b/media/mp4/mp4_stream_parser.h @@ -11,6 +11,7 @@ #include "base/memory/scoped_ptr.h" #include "media/base/media_export.h" #include "media/base/stream_parser.h" +#include "media/mp4/aac.h" #include "media/mp4/offset_byte_queue.h" #include "media/mp4/track_run_iterator.h" @@ -85,8 +86,9 @@ class MEDIA_EXPORT MP4StreamParser : public StreamParser { uint32 audio_track_id_; uint32 video_track_id_; - // We keep this around to avoid having to go digging through the moov with + // We keep them around to avoid having to go digging through the moov with // every frame. + AAC aac_; uint8 size_of_nalu_length_; DISALLOW_COPY_AND_ASSIGN(MP4StreamParser); |