Index: media/base/ac3_util.cc |
diff --git a/media/base/ac3_util.cc b/media/base/ac3_util.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..849e2b94a6a8eae6800c6b39323bd846e32c9258 |
--- /dev/null |
+++ b/media/base/ac3_util.cc |
@@ -0,0 +1,169 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
DaleCurtis
2016/12/14 20:00:03
Probably want to use a BitReader here instead. Syn
AndyWu
2016/12/15 22:20:02
Done, thanks. I still keep the weird abbreviations
|
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "media/base/ac3_util.h" |
+ |
+#include "base/logging.h" |
+#include "base/macros.h" |
+ |
+namespace media { |
+ |
+namespace { |
+ |
+// The size in byte of a (E-)AC3 syncframe header. |
+const int kHeaderSizeInByte = 8; |
+// The number of new samples per (E-)AC3 audio block. |
+const int kAudioSamplesPerAudioBlock = 256; |
+// Each syncframe has 6 blocks that provide 256 new audio samples. See ETSI TS |
+// 102 366 4.1. |
+const int kAc3SyncframeAudioSampleCount = 6 * kAudioSamplesPerAudioBlock; |
+// Number of audio blocks per E-AC3 syncframe, indexed by numblkscod. |
+const int kBlocksPerSyncframeByNumblkscod[] = {1, 2, 3, 6}; |
+// Sample rates, indexed by fscod. |
+const int kSampleRateByFscod[] = {48000, 44100, 32000}; |
+// Nominal bitrates in kbps, indexed by frmsizecod / 2. (See ETSI TS 102 366 |
+// table 4.13.) |
+const int kBitrateByHalfFrmsizecod[] = {32, 40, 48, 56, 64, 80, 96, |
+ 112, 128, 160, 192, 224, 256, 320, |
+ 384, 448, 512, 576, 640}; |
+// 16-bit words per syncframe, indexed by frmsizecod / 2. (See ETSI TS 102 366 |
+// table 4.13.) |
+const int kSyncframeSizeWordsByHalfFrmsizecod441[] = { |
+ 69, 87, 104, 121, 139, 174, 208, 243, 278, 348, |
+ 417, 487, 557, 696, 835, 975, 1114, 1253, 1393}; |
+ |
+// Search for next syncword, wihch is 0x0B-0x77. |
+const uint8_t* FindNextSync(const uint8_t* const begin, |
+ const uint8_t* const end) { |
+ DCHECK(begin); |
+ DCHECK(end); |
+ DCHECK_LE(begin, end); |
+ |
+ const uint8_t* current = begin; |
+ |
+ while (current < end - 1) { |
DaleCurtis
2016/12/14 20:00:03
You can scan two bytes at a time by check current[
AndyWu
2016/12/15 22:20:02
Done.
|
+ if (current[0] == 0x0B && current[1] == 0x77) { |
+ if (current != begin) |
+ DVLOG(2) << __FUNCTION__ << " skip " << current - begin << " bytes."; |
+ |
+ return current; |
+ } |
+ ++current; |
+ } |
+ |
+ return nullptr; |
+} |
+ |
+// Returns the number of audio samples represented by the given E-AC3 syncframe. |
+int ParseEac3SyncframeSampleCount(const uint8_t* const data, |
+ const uint8_t* const end) { |
+ DCHECK(data); |
+ DCHECK(end); |
+ DCHECK_GE(end - data, kHeaderSizeInByte); |
+ |
+ return kAudioSamplesPerAudioBlock * |
+ (((data[4] & 0xC0) >> 6) == 0x03 |
+ ? 6 |
+ : kBlocksPerSyncframeByNumblkscod[(data[4] & 0x30) >> 4]); |
+} |
+ |
+// Returns the size in bytes of the given E-AC3 syncframe. |
+int ParseEac3SyncframeSize(const uint8_t* const data, |
+ const uint8_t* const end) { |
+ DCHECK(data); |
+ DCHECK(end); |
+ DCHECK_GE(end - data, kHeaderSizeInByte); |
+ |
+ return 2 * (((data[2] & 0x07) << 8) + (data[3] & 0xFF) + 1); |
+} |
+ |
+// Returns the number of audio samples in an AC3 syncframe. |
+int GetAc3SyncframeSampleCount() { |
+ return kAc3SyncframeAudioSampleCount; |
+} |
+ |
+// Returns the size in bytes of the given AC3 syncframe. |
+int ParseAc3SyncframeSize(const uint8_t* const data, const uint8_t* const end) { |
+ DCHECK(data); |
+ DCHECK(end); |
+ DCHECK_GE(end - data, kHeaderSizeInByte); |
+ |
+ unsigned fscod = (data[4] & 0xC0) >> 6; |
+ unsigned frmsizecod = data[4] & 0x3F; |
+ unsigned half_frmsizecod = frmsizecod / 2; |
+ |
+ if (fscod >= arraysize(kSampleRateByFscod) || |
+ half_frmsizecod >= arraysize(kSyncframeSizeWordsByHalfFrmsizecod441)) { |
+ DVLOG(2) << __FUNCTION__ << " Invalid frame header." |
+ << " fscod:" << fscod << " half_frmsizecod:" << half_frmsizecod; |
+ return -1; |
+ } |
+ |
+ int sample_rate = kSampleRateByFscod[fscod]; |
+ if (sample_rate == 44100) { |
+ return 2 * (kSyncframeSizeWordsByHalfFrmsizecod441[half_frmsizecod] + |
+ (frmsizecod % 2)); |
+ } |
+ |
+ int bitrate = kBitrateByHalfFrmsizecod[half_frmsizecod]; |
DaleCurtis
2016/12/14 20:00:03
Don't use else blocks with return.
AndyWu
2016/12/15 22:20:03
Done.
|
+ if (sample_rate == 32000) { |
+ return 6 * bitrate; |
+ } else { // sample_rate == 48000 |
+ return 4 * bitrate; |
+ } |
+} |
+ |
+// Returns the total number of audio samples in the given buffer, which contains |
+// several complete (E-)AC3 syncframes. |
+int ParseTotalSampleCount(const uint8_t* data, size_t size, bool is_eac3) { |
+ DCHECK(data); |
+ |
+ if (size < kHeaderSizeInByte) { |
+ return 0; |
+ } |
+ |
+ const uint8_t* const end = data + size; |
+ const uint8_t* current = FindNextSync(data, end); |
+ int total_sample_count = 0; |
+ |
+ while (current && end - current > kHeaderSizeInByte) { |
+ int frame_size = is_eac3 ? ParseEac3SyncframeSize(current, end) |
+ : ParseAc3SyncframeSize(current, end); |
+ int sample_count = is_eac3 ? ParseEac3SyncframeSampleCount(current, end) |
+ : GetAc3SyncframeSampleCount(); |
+ |
+ if (frame_size > 0 && sample_count > 0) { |
+ current += frame_size; |
+ if (current > end) { |
+ DVLOG(2) << __FUNCTION__ << " Incomplete frame, missing " |
+ << current - end << " bytes."; |
+ break; |
+ } |
+ |
+ total_sample_count += sample_count; |
+ } else { |
+ DVLOG(2) << __FUNCTION__ |
+ << " Invalid frame, skip 2 bytes to find next syncword."; |
+ current += 2; |
+ } |
+ |
+ current = FindNextSync(current, end); |
+ } |
+ |
+ return total_sample_count; |
+} |
+ |
+} // namespace anonymous |
+ |
+// static |
+int Ac3Util::ParseTotalAc3SampleCount(const uint8_t* data, size_t size) { |
+ return ParseTotalSampleCount(data, size, false); |
+} |
+ |
+// static |
+int Ac3Util::ParseTotalEac3SampleCount(const uint8_t* data, size_t size) { |
+ return ParseTotalSampleCount(data, size, true); |
+} |
+ |
+} // namespace media |