Chromium Code Reviews| 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 |