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 |