7#include <packager/media/codecs/ec3_audio_util.h>
14#include <absl/log/check.h>
15#include <absl/log/log.h>
16#include <absl/strings/escaping.h>
18#include <packager/media/base/bit_reader.h>
19#include <packager/media/base/rcheck.h>
20#include <packager/utils/bytes_to_string_view.h>
45enum kEC3AudioChannelMap {
49 kLeftSurround = 0x1000,
50 kRightSurround = 0x800,
53 kCenterSurround = 0x100,
54 kTopCenterSurround = 0x80,
58 kCenterVerticalHeight = 0x8,
65const size_t kChannelCountArray[] = {
66 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1, 2, 1, 1,
68static_assert(std::size(kChannelCountArray) == 16u,
69 "Channel count array should have 16 entries.");
74const uint16_t kEC3AudioCodingModeMap[] = {
78 kLeft | kCenter | kRight,
79 kLeft | kRight | kLeftSurround | kRightSurround,
80 kLeft | kCenter | kRight | kLeftSurround | kRightSurround,
81 kLeft | kRight | kLeftSurround | kRightSurround,
82 kLeft | kCenter | kRight | kLeftSurround | kRightSurround,
86uint8_t ReverseBits8(uint8_t n) {
87 n = ((n >> 1) & 0x55) | ((n & 0x55) << 1);
88 n = ((n >> 2) & 0x33) | ((n & 0x33) << 2);
89 return ((n >> 4) & 0x0f) | ((n & 0x0f) << 4);
95uint32_t EC3ChannelMaptoMPEGValue(uint32_t channel_map) {
98 switch (channel_map) {
105 case kCenter | kLeft | kRight:
108 case kCenter | kLeft | kRight | kCenterSurround:
111 case kCenter | kLeft | kRight | kLeftSurround | kRightSurround:
114 case kCenter | kLeft | kRight | kLeftSurround | kRightSurround | kLFEScreen:
117 case kCenter | kLeft | kRight | kLwRwPair | kLeftSurround | kRightSurround |
121 case kLeft | kRight | kCenterSurround:
124 case kLeft | kRight | kLeftSurround | kRightSurround:
127 case kCenter | kLeft | kRight | kLrsRrsPair | kCenterSurround | kLFEScreen:
130 case kCenter | kLeft | kRight | kLeftSurround | kRightSurround |
131 kLrsRrsPair | kLFEScreen:
134 case kCenter | kLeft | kRight | kLeftSurround | kRightSurround |
135 kLFEScreen | kLvhRvhPair:
138 case kCenter | kLeft | kRight | kLeftSurround | kRightSurround |
139 kLFEScreen | kLvhRvhPair | kLtsRtsPair:
142 case kCenter | kLeft | kRight | kLeftSurround | kRightSurround |
143 kLFEScreen | kLvhRvhPair | kCenterVerticalHeight | kLtsRtsPair |
147 case kCenter | kLeft | kRight | kLsdRsdPair | kLrsRrsPair | kLFEScreen |
148 kLvhRvhPair | kLtsRtsPair:
157bool ExtractEc3Data(
const std::vector<uint8_t>& ec3_data,
158 uint8_t* audio_coding_mode,
159 bool* lfe_channel_on,
160 uint16_t* dependent_substreams_layout,
161 uint32_t* ec3_joc_complexity) {
162 BitReader bit_reader(ec3_data.data(), ec3_data.size());
164 uint8_t number_independent_substreams;
165 RCHECK(bit_reader.SkipBits(13) &&
166 bit_reader.ReadBits(3, &number_independent_substreams));
169 ++number_independent_substreams;
187 RCHECK(bit_reader.SkipBits(12));
188 RCHECK(bit_reader.ReadBits(3, audio_coding_mode));
189 RCHECK(bit_reader.ReadBits(1, lfe_channel_on));
191 uint8_t number_dependent_substreams = 0;
192 RCHECK(bit_reader.SkipBits(3));
193 RCHECK(bit_reader.ReadBits(4, &number_dependent_substreams));
195 *dependent_substreams_layout = 0;
196 if (number_dependent_substreams > 0) {
197 RCHECK(bit_reader.ReadBits(9, dependent_substreams_layout));
199 RCHECK(bit_reader.SkipBits(1));
201 *ec3_joc_complexity = 0;
202 if (bit_reader.bits_available() < 16) {
206 RCHECK(bit_reader.SkipBits(7));
208 RCHECK(bit_reader.ReadBits(1, &ec3_joc_flag));
210 RCHECK(bit_reader.ReadBits(8, ec3_joc_complexity));
217bool CalculateEC3ChannelMap(
const std::vector<uint8_t>& ec3_data,
218 uint32_t* channel_map) {
219 uint8_t audio_coding_mode;
221 uint16_t dependent_substreams_layout;
222 uint32_t ec3_joc_complexity;
223 if (!ExtractEc3Data(ec3_data, &audio_coding_mode, &lfe_channel_on,
224 &dependent_substreams_layout, &ec3_joc_complexity)) {
225 LOG(WARNING) <<
"Seeing invalid EC3 data: "
226 << absl::BytesToHexString(
244 const uint8_t reversed_dependent_substreams_layout =
245 ReverseBits8(dependent_substreams_layout & 0xFF);
247 *channel_map = kEC3AudioCodingModeMap[audio_coding_mode] |
248 (reversed_dependent_substreams_layout << 3);
249 if (dependent_substreams_layout & 0x100)
250 *channel_map |= kLFE2;
252 *channel_map |= kLFEScreen;
256bool CalculateEC3ChannelMPEGValue(
const std::vector<uint8_t>& ec3_data,
257 uint32_t* ec3_channel_mpeg_value) {
258 uint32_t channel_map;
259 if (!CalculateEC3ChannelMap(ec3_data, &channel_map))
261 *ec3_channel_mpeg_value = EC3ChannelMaptoMPEGValue(channel_map);
265size_t GetEc3NumChannels(
const std::vector<uint8_t>& ec3_data) {
266 uint32_t channel_map;
267 if (!CalculateEC3ChannelMap(ec3_data, &channel_map))
270 size_t num_channels = 0;
272 for (
size_t channel_count : kChannelCountArray) {
273 if (channel_map & bit)
274 num_channels += channel_count;
281bool GetEc3JocComplexity(
const std::vector<uint8_t>& ec3_data,
282 uint32_t* ec3_joc_complexity) {
283 uint8_t audio_coding_mode;
285 uint16_t dependent_substreams_layout;
287 if (!ExtractEc3Data(ec3_data, &audio_coding_mode, &lfe_channel_on,
288 &dependent_substreams_layout, ec3_joc_complexity)) {
289 LOG(WARNING) <<
"Seeing invalid EC3 data: "
290 << 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.