7#include <packager/media/codecs/ec3_audio_util.h>
9#include <absl/log/check.h>
10#include <absl/strings/escaping.h>
12#include <packager/media/base/bit_reader.h>
13#include <packager/media/base/rcheck.h>
14#include <packager/utils/bytes_to_string_view.h>
39enum kEC3AudioChannelMap {
43 kLeftSurround = 0x1000,
44 kRightSurround = 0x800,
47 kCenterSurround = 0x100,
48 kTopCenterSurround = 0x80,
52 kCenterVerticalHeight = 0x8,
59const size_t kChannelCountArray[] = {
60 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1, 2, 1, 1,
62static_assert(std::size(kChannelCountArray) == 16u,
63 "Channel count array should have 16 entries.");
68const uint16_t kEC3AudioCodingModeMap[] = {
72 kLeft | kCenter | kRight,
73 kLeft | kRight | kLeftSurround | kRightSurround,
74 kLeft | kCenter | kRight | kLeftSurround | kRightSurround,
75 kLeft | kRight | kLeftSurround | kRightSurround,
76 kLeft | kCenter | kRight | kLeftSurround | kRightSurround,
80uint8_t ReverseBits8(uint8_t n) {
81 n = ((n >> 1) & 0x55) | ((n & 0x55) << 1);
82 n = ((n >> 2) & 0x33) | ((n & 0x33) << 2);
83 return ((n >> 4) & 0x0f) | ((n & 0x0f) << 4);
89uint32_t EC3ChannelMaptoMPEGValue(uint32_t channel_map) {
92 switch (channel_map) {
99 case kCenter | kLeft | kRight:
102 case kCenter | kLeft | kRight | kCenterSurround:
105 case kCenter | kLeft | kRight | kLeftSurround | kRightSurround:
108 case kCenter | kLeft | kRight | kLeftSurround | kRightSurround | kLFEScreen:
111 case kCenter | kLeft | kRight | kLwRwPair | kLeftSurround | kRightSurround |
115 case kLeft | kRight | kCenterSurround:
118 case kLeft | kRight | kLeftSurround | kRightSurround:
121 case kCenter | kLeft | kRight | kLrsRrsPair | kCenterSurround | kLFEScreen:
124 case kCenter | kLeft | kRight | kLeftSurround | kRightSurround |
125 kLrsRrsPair | kLFEScreen:
128 case kCenter | kLeft | kRight | kLeftSurround | kRightSurround |
129 kLFEScreen | kLvhRvhPair:
132 case kCenter | kLeft | kRight | kLeftSurround | kRightSurround |
133 kLFEScreen | kLvhRvhPair | kLtsRtsPair:
136 case kCenter | kLeft | kRight | kLeftSurround | kRightSurround |
137 kLFEScreen | kLvhRvhPair | kCenterVerticalHeight | kLtsRtsPair |
141 case kCenter | kLeft | kRight | kLsdRsdPair | kLrsRrsPair | kLFEScreen |
142 kLvhRvhPair | kLtsRtsPair:
151bool ExtractEc3Data(
const std::vector<uint8_t>& ec3_data,
152 uint8_t* audio_coding_mode,
153 bool* lfe_channel_on,
154 uint16_t* dependent_substreams_layout,
155 uint32_t* ec3_joc_complexity) {
156 BitReader bit_reader(ec3_data.data(), ec3_data.size());
158 uint8_t number_independent_substreams;
159 RCHECK(bit_reader.SkipBits(13) &&
160 bit_reader.ReadBits(3, &number_independent_substreams));
163 ++number_independent_substreams;
181 RCHECK(bit_reader.SkipBits(12));
182 RCHECK(bit_reader.ReadBits(3, audio_coding_mode));
183 RCHECK(bit_reader.ReadBits(1, lfe_channel_on));
185 uint8_t number_dependent_substreams = 0;
186 RCHECK(bit_reader.SkipBits(3));
187 RCHECK(bit_reader.ReadBits(4, &number_dependent_substreams));
189 *dependent_substreams_layout = 0;
190 if (number_dependent_substreams > 0) {
191 RCHECK(bit_reader.ReadBits(9, dependent_substreams_layout));
193 RCHECK(bit_reader.SkipBits(1));
195 *ec3_joc_complexity = 0;
196 if (bit_reader.bits_available() < 16) {
200 RCHECK(bit_reader.SkipBits(7));
202 RCHECK(bit_reader.ReadBits(1, &ec3_joc_flag));
204 RCHECK(bit_reader.ReadBits(8, ec3_joc_complexity));
211bool CalculateEC3ChannelMap(
const std::vector<uint8_t>& ec3_data,
212 uint32_t* channel_map) {
213 uint8_t audio_coding_mode;
215 uint16_t dependent_substreams_layout;
216 uint32_t ec3_joc_complexity;
217 if (!ExtractEc3Data(ec3_data, &audio_coding_mode, &lfe_channel_on,
218 &dependent_substreams_layout, &ec3_joc_complexity)) {
219 LOG(WARNING) <<
"Seeing invalid EC3 data: "
220 << absl::BytesToHexString(
238 const uint8_t reversed_dependent_substreams_layout =
239 ReverseBits8(dependent_substreams_layout & 0xFF);
241 *channel_map = kEC3AudioCodingModeMap[audio_coding_mode] |
242 (reversed_dependent_substreams_layout << 3);
243 if (dependent_substreams_layout & 0x100)
244 *channel_map |= kLFE2;
246 *channel_map |= kLFEScreen;
250bool CalculateEC3ChannelMPEGValue(
const std::vector<uint8_t>& ec3_data,
251 uint32_t* ec3_channel_mpeg_value) {
252 uint32_t channel_map;
253 if (!CalculateEC3ChannelMap(ec3_data, &channel_map))
255 *ec3_channel_mpeg_value = EC3ChannelMaptoMPEGValue(channel_map);
259size_t GetEc3NumChannels(
const std::vector<uint8_t>& ec3_data) {
260 uint32_t channel_map;
261 if (!CalculateEC3ChannelMap(ec3_data, &channel_map))
264 size_t num_channels = 0;
266 for (
size_t channel_count : kChannelCountArray) {
267 if (channel_map & bit)
268 num_channels += channel_count;
275bool GetEc3JocComplexity(
const std::vector<uint8_t>& ec3_data,
276 uint32_t* ec3_joc_complexity) {
277 uint8_t audio_coding_mode;
279 uint16_t dependent_substreams_layout;
281 if (!ExtractEc3Data(ec3_data, &audio_coding_mode, &lfe_channel_on,
282 &dependent_substreams_layout, ec3_joc_complexity)) {
283 LOG(WARNING) <<
"Seeing invalid EC3 data: "
284 << absl::BytesToHexString(
All the methods that are virtual are virtual for mocking.
std::string_view byte_vector_to_string_view(const std::vector< uint8_t > &bytes)
Convert byte vector to string_view.