summaryrefslogtreecommitdiffstats
path: root/media/mp4
diff options
context:
space:
mode:
Diffstat (limited to 'media/mp4')
-rw-r--r--media/mp4/aac.cc252
-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.cc28
-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.cc16
-rw-r--r--media/mp4/mp4_stream_parser.h4
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);