Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1264)

Unified Diff: media/mp4/aac.cc

Issue 10710002: Add HE AAC support to ISO BMFF. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Add unittest for 5.1 channel. Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: media/mp4/aac.cc
diff --git a/media/mp4/aac.cc b/media/mp4/aac.cc
new file mode 100644
index 0000000000000000000000000000000000000000..b5285ada95ea6a3a7fb8d978208540d1086a9588
--- /dev/null
+++ b/media/mp4/aac.cc
@@ -0,0 +1,311 @@
+// 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"
+
+namespace {
acolwell GONE FROM CHROMIUM 2012/06/28 17:31:25 Remove. The media code does not use anonymous name
+
+// The following conversion table is extracted from ISO 14496 Part 3
+// "Table 1.16 — Sampling Frequency Index".
+static const uint32_t kFrequencyMap[] = {
acolwell GONE FROM CHROMIUM 2012/06/28 17:31:25 Change to uint32
+ 96000, 88200, 64000, 48000, 44100, 32000, 24000,
+ 22050, 16000, 12000, 11025, 8000, 7350
+};
+
+// 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.
+bool ReadESSize(const std::vector<uint8>& esds, size_t* offset, uint32* size) {
+ uint8 byte;
+
+ *size = 0;
+
+ for (size_t i = 0; i < 4; ++i) {
+ RCHECK(*offset < esds.size());
+
+ byte = esds[*offset];
+ ++*offset;
+ *size = *size * 128 + (byte & 0x7f);
acolwell GONE FROM CHROMIUM 2012/06/28 17:31:25 Use << here
+
+ if ((byte & 0x80) == 0)
+ break;
+ }
+
+ return true;
+}
+
+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;
+}
+
+// This functions parses the binary data from esds box to get elementary
+// stream descriptor.
+bool ExtractDescriptor(const std::vector<uint8>& esds,
+ std::vector<uint8>* descriptor) {
+ uint8 tag;
+ uint32 size;
+ size_t offset = 0;
+
+ while (offset < esds.size()) {
+ tag = esds[offset];
+ ++offset;
+
+ RCHECK(ReadESSize(esds, &offset, &size));
+
+ if (tag == 3) {
+ offset += 3;
+ } else if (tag == 4) {
+ offset += 13;
+ } else if (tag == 5) {
+ RCHECK(offset + size <= esds.size());
+ descriptor->assign(esds.begin() + offset, esds.begin() + offset + size);
+ offset += size;
+ } else if (tag == 6) {
+ offset += 1;
+ } else {
+ break;
+ }
+ }
+
+ return !descriptor->empty();
+}
+
+} // anonymous namespace
+
+namespace media {
+
+namespace mp4 {
+
+AAC::AAC()
+ : profile_(0), frequency_index_(0), channel_config_(0),
+ frequency_(0), channel_layout_(CHANNEL_LAYOUT_UNSUPPORTED) {
acolwell GONE FROM CHROMIUM 2012/06/28 17:31:25 Add 2 indent spaces.
+}
+
+AAC::~AAC() {
+}
+
+bool AAC::Initialize(const std::vector<uint8>& esds) {
+ BitReader reader;
+ uint8 extension_type = 0;
+ bool ps_present = false;
+ uint8 extension_frequency_index;
+ std::vector<uint8> descriptor;
+
+ profile_ = 0;
+ frequency_index_ = 0;
+ frequency_ = 0;
+ channel_config_ = 0;
+
+ RCHECK(ExtractDescriptor(esds, &descriptor));
+ reader.Initialize(&descriptor[0], descriptor.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(&reader));
+
+ // 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 <
+ sizeof(kFrequencyMap) / sizeof(*kFrequencyMap));
acolwell GONE FROM CHROMIUM 2012/06/28 17:31:25 used arraysize(kFrequencyMap) here instead of size
+ 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);
+
+ if (size <= 8192) {
acolwell GONE FROM CHROMIUM 2012/06/28 17:31:25 reverse condition and return early so that you don
+ std::vector<uint8>& adts = *buffer;
+
+ adts.insert(buffer->begin(), 7, 0);
+ adts[0] = 0xff;
+ adts[1] = 0xf1;
+ adts[2] = (profile_ - 1) * 64 + frequency_index_ * 4 + channel_config_ / 4;
acolwell GONE FROM CHROMIUM 2012/06/28 17:31:25 Please use << instead of * for all shifting and us
+ adts[3] = channel_config_ % 4 * 64 + size / 2048;
+ adts[4] = size % 2048 / 8;
+ adts[5] = size % 8 * 32 + 0x1f;
+ adts[6] = 0xfc;
+
+ return true;
+ }
+
+ return false;
+}
+
+// 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(BitReader* bit_reader) const {
acolwell GONE FROM CHROMIUM 2012/06/28 17:31:25 Remove bit_reader parameter. It isn't used by this
+ 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

Powered by Google App Engine
This is Rietveld 408576698