summaryrefslogtreecommitdiffstats
path: root/media/mp4
diff options
context:
space:
mode:
authorxiaomings@google.com <xiaomings@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-19 19:43:45 +0000
committerxiaomings@google.com <xiaomings@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-19 19:43:45 +0000
commit279a07fae05681f3d40f1466e3c4aa8e3e67028b (patch)
tree1081535465632787800ab0fd933e69dd88f2c051 /media/mp4
parent968ff687d1cd2608cfbe8af26b8f352587074f40 (diff)
downloadchromium_src-279a07fae05681f3d40f1466e3c4aa8e3e67028b.zip
chromium_src-279a07fae05681f3d40f1466e3c4aa8e3e67028b.tar.gz
chromium_src-279a07fae05681f3d40f1466e3c4aa8e3e67028b.tar.bz2
Add HE AAC support to ISO BMFF.
Was https://chromiumcodereview.appspot.com/10753005/. The original cl also includes abstraction of BitReader class used by H264Parser. It includes bugs that break the H264Parser. In this cl I removed the abstraction and make the BitReader used by H264Parser independent to the one used by esds parser because of: 1. The original cl introduce bugs. 2. Even if we fix the bugs, we may not be able to make the generalized class as fast as the old one while keeping the abstraction. 3. The H264 bit stream use very special syntax on escaping and trailing zero bits, which might not be a good candidate for abstraction. BUG=134445 TEST=BitReaderTest, AACTest Review URL: https://chromiumcodereview.appspot.com/10780026 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@147511 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/mp4')
-rw-r--r--media/mp4/aac.cc246
-rw-r--r--media/mp4/aac.h67
-rw-r--r--media/mp4/aac_unittest.cc104
-rw-r--r--media/mp4/avc.cc22
-rw-r--r--media/mp4/avc.h4
-rw-r--r--media/mp4/box_definitions.cc29
-rw-r--r--media/mp4/box_definitions.h9
-rw-r--r--media/mp4/es_descriptor.cc112
-rw-r--r--media/mp4/es_descriptor.h57
-rw-r--r--media/mp4/es_descriptor_unittest.cc92
-rw-r--r--media/mp4/mp4_stream_parser.cc17
11 files changed, 727 insertions, 32 deletions
diff --git a/media/mp4/aac.cc b/media/mp4/aac.cc
new file mode 100644
index 0000000..01c831d
--- /dev/null
+++ b/media/mp4/aac.cc
@@ -0,0 +1,246 @@
+// 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) {
+ if (data.empty())
+ return false;
+
+ BitReader reader(&data[0], data.size());
+ uint8 extension_type = 0;
+ bool ps_present = false;
+ uint8 extension_frequency_index;
+
+ frequency_ = 0;
+
+ // 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) {
+ uint16 sync_extension_type;
+ uint8 sbr_present_flag;
+ uint8 ps_present_flag;
+
+ if (reader.ReadBits(11, &sync_extension_type) &&
+ sync_extension_type == 0x2b7) {
+ if (reader.ReadBits(5, &extension_type) && 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(2);
+ 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))
+ 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;
+ uint16 dummy;
+
+ RCHECK(bit_reader->ReadBits(1, &dummy)); // frameLengthFlag
+ RCHECK(bit_reader->ReadBits(1, &depends_on_core_coder));
+ if (depends_on_core_coder == 1)
+ RCHECK(bit_reader->ReadBits(14, &dummy)); // coreCoderDelay
+
+ RCHECK(bit_reader->ReadBits(1, &extension_flag));
+ RCHECK(channel_config_ != 0);
+
+ if (profile_ == 6 || profile_ == 20)
+ RCHECK(bit_reader->ReadBits(3, &dummy)); // layerNr
+
+ if (extension_flag) {
+ if (profile_ == 22) {
+ RCHECK(bit_reader->ReadBits(5, &dummy)); // numOfSubFrame
+ RCHECK(bit_reader->ReadBits(11, &dummy)); // layer_length
+ }
+
+ if (profile_ == 17 || profile_ == 19 || profile_ == 20 || profile_ == 23) {
+ RCHECK(bit_reader->ReadBits(3, &dummy)); // resilience flags
+ }
+
+ RCHECK(bit_reader->ReadBits(1, &dummy)); // extensionFlag3
+ }
+
+ 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 f9d2bcc..ebfeae7 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,30 @@ bool VideoSampleEntry::Parse(BoxReader* reader) {
return true;
}
+ElementaryStreamDescriptor::ElementaryStreamDescriptor()
+ : object_type(kForbidden) {}
+
+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 +420,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 +443,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 7f7384b..0b19a5c 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 MEDIA_EXPORT VideoSampleEntry : Box {
AVCDecoderConfigurationRecord avcc;
};
+struct MEDIA_EXPORT ElementaryStreamDescriptor : Box {
+ DECLARE_BOX_METHODS(ElementaryStreamDescriptor);
+
+ uint8 object_type;
+ AAC aac;
+};
+
struct MEDIA_EXPORT AudioSampleEntry : Box {
DECLARE_BOX_METHODS(AudioSampleEntry);
@@ -194,6 +202,7 @@ struct MEDIA_EXPORT AudioSampleEntry : Box {
uint32 samplerate;
ProtectionSchemeInfo sinf;
+ ElementaryStreamDescriptor esds;
};
struct MEDIA_EXPORT SampleDescription : Box {
diff --git a/media/mp4/es_descriptor.cc b/media/mp4/es_descriptor.cc
new file mode 100644
index 0000000..f9480dd
--- /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;
+ uint16 dummy;
+
+ RCHECK(reader.ReadBits(8, &tag));
+ RCHECK(tag == kESDescrTag);
+ RCHECK(ReadESSize(&reader, &size));
+
+ RCHECK(reader.ReadBits(16, &dummy)); // ES_ID
+ RCHECK(reader.ReadBits(1, &stream_dependency_flag));
+ RCHECK(reader.ReadBits(1, &url_flag));
+ RCHECK(!url_flag); // We don't support url flag
+ RCHECK(reader.ReadBits(1, &ocr_stream_flag));
+ RCHECK(reader.ReadBits(5, &dummy)); // streamPriority
+
+ if (stream_dependency_flag)
+ RCHECK(reader.ReadBits(16, &dummy)); // dependsOn_ES_ID
+ if (ocr_stream_flag)
+ RCHECK(reader.ReadBits(16, &dummy)); // 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;
+ uint64 dummy;
+
+ RCHECK(reader->ReadBits(8, &tag));
+ RCHECK(tag == kDecoderConfigDescrTag);
+ RCHECK(ReadESSize(reader, &size));
+
+ RCHECK(reader->ReadBits(8, &object_type_));
+ RCHECK(reader->ReadBits(64, &dummy));
+ RCHECK(reader->ReadBits(32, &dummy));
+ 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));
+
+ 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 06f521b..45d81db 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 {
@@ -175,6 +176,7 @@ bool MP4StreamParser::ParseMoov(BoxReader* reader) {
if (static_cast<uint32>(desc_idx) >= samp_descr.audio_entries.size())
desc_idx = 0;
const AudioSampleEntry& entry = samp_descr.audio_entries[desc_idx];
+ const AAC& aac = entry.esds.aac;
// TODO(strobe): We accept all format values, pending clarification on
// the formats used for encrypted media (http://crbug.com/132351).
@@ -182,10 +184,12 @@ 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);
+ 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,11 @@ bool MP4StreamParser::EnqueueSample(BufferQueue* audio_buffers,
RCHECK(AVC::InsertParameterSets(avc_config, &frame_buf));
}
+ if (audio) {
+ const AAC& aac = runs_->audio_description().esds.aac;
+ RCHECK(aac.ConvertEsdsToADTS(&frame_buf));
+ }
+
scoped_refptr<StreamParserBuffer> stream_buf =
StreamParserBuffer::CopyFrom(&frame_buf[0], frame_buf.size(),
runs_->is_keyframe());