Shaka Packager SDK
Loading...
Searching...
No Matches
ac4_audio_util.cc
1// Copyright 2020 Google LLC. All rights reserved.
2//
3// Use of this source code is governed by a BSD-style
4// license that can be found in the LICENSE file or at
5// https://developers.google.com/open-source/licenses/bsd
6
7#include <packager/media/codecs/ac4_audio_util.h>
8
9#include <cstddef>
10#include <cstdint>
11#include <vector>
12
13#include <absl/log/log.h>
14#include <absl/strings/escaping.h>
15
16#include <packager/media/base/bit_reader.h>
17#include <packager/media/base/rcheck.h>
18#include <packager/utils/bytes_to_string_view.h>
19
20namespace shaka {
21namespace media {
22
23namespace {
24
25// Speaker group index
26// Bit, Location
27// 0(LSB), Left/Right pair
28// 1, Centre
29// 2, Left surround/Right surround pair
30// 3, Left back/Right back pair
31// 4, Top front left/Top front right pair
32// 5, Top back left/Top back right pair
33// 6, LFE
34// 7, Top left/Top right pair
35// 8, Top side left/Top side right pair
36// 9, Top front centre
37// 10, Top back centre
38// 11, Top centre
39// 12, LFE2
40// 13, Bottom front left/Bottom front right pair
41// 14, Bottom front centre
42// 15, Back centre
43// 16, Left screen/Right screen pair
44// 17, Left wide/Right wide pair
45// 18, Vertical height left/Vertical height right pair
46enum kAC4AudioChannelGroupIndex {
47 kLRPair = 0x1,
48 kCentre = 0x2,
49 kLsRsPair = 0x4,
50 kLbRbPair = 0x8,
51 kTflTfrPair = 0x10,
52 kTblTbrPair = 0x20,
53 kLFE = 0x40,
54 kTlTrPair = 0x80,
55 kTslTsrPair = 0x100,
56 kTopfrontCentre = 0x200,
57 kTopbackCentre = 0x400,
58 kTopCentre = 0x800,
59 kLFE2 = 0x1000,
60 kBflBfrPair = 0x2000,
61 kBottomFrontCentre = 0x4000,
62 kBackCentre = 0x8000,
63 kLscrRscrPair = 0x10000,
64 kLwRw = 0x20000,
65 kVhlVhrPair = 0x40000,
66};
67
68// Mapping of channel configurations to the MPEG audio value based on ETSI TS
69// 103 192-2 V1.2.1 Digital Audio Compression (AC-4) Standard;
70// Part 2: Immersive and personalized Table G.1
71uint32_t AC4ChannelMasktoMPEGValue(uint32_t channel_mask) {
72 uint32_t ret = 0;
73
74 switch (channel_mask) {
75 case kCentre:
76 ret = 1;
77 break;
78 case kLRPair:
79 ret = 2;
80 break;
81 case kCentre | kLRPair:
82 ret = 3;
83 break;
84 case kCentre | kLRPair | kBackCentre:
85 ret = 4;
86 break;
87 case kCentre | kLRPair | kLsRsPair:
88 ret = 5;
89 break;
90 case kCentre | kLRPair | kLsRsPair | kLFE:
91 ret = 6;
92 break;
93 case kCentre | kLRPair | kLsRsPair | kLFE | kLwRw:
94 ret = 7;
95 break;
96 case kBackCentre | kLRPair:
97 ret = 9;
98 break;
99 case kLRPair | kLsRsPair:
100 ret = 10;
101 break;
102 case kCentre | kLRPair | kLsRsPair | kLFE | kBackCentre:
103 ret = 11;
104 break;
105 case kCentre | kLRPair | kLsRsPair | kLbRbPair | kLFE:
106 ret = 12;
107 break;
108 case kLwRw | kBackCentre | kBottomFrontCentre | kBflBfrPair | kLFE2 |
109 kTopCentre | kTopbackCentre | kTopfrontCentre | kTslTsrPair | kLFE |
110 kTblTbrPair | kTflTfrPair | kLbRbPair | kLsRsPair | kCentre | kLRPair:
111 case kVhlVhrPair | kLwRw | kBackCentre | kBottomFrontCentre | kBflBfrPair |
112 kLFE2 | kTopCentre | kTopbackCentre | kTopfrontCentre | kTslTsrPair |
113 kLFE | kTblTbrPair | kLbRbPair | kLsRsPair | kCentre | kLRPair:
114 ret = 13;
115 break;
116 case kLFE | kTflTfrPair | kLsRsPair | kCentre | kLRPair:
117 case kVhlVhrPair | kLFE | kCentre | kLRPair | kLsRsPair:
118 ret = 14;
119 break;
120 case kLFE2 | kTopbackCentre | kLFE | kTflTfrPair | kCentre | kLRPair |
121 kLsRsPair | kLbRbPair:
122 case kVhlVhrPair | kLFE2 | kTopbackCentre | kLFE | kCentre | kLRPair |
123 kLsRsPair | kLbRbPair:
124 ret = 15;
125 break;
126 case kLFE | kTblTbrPair | kTflTfrPair | kLsRsPair | kCentre | kLRPair:
127 case kVhlVhrPair | kLFE | kTblTbrPair | kLsRsPair | kCentre | kLRPair:
128 ret = 16;
129 break;
130 case kTopCentre | kTopfrontCentre | kLFE | kTblTbrPair | kTflTfrPair |
131 kLsRsPair | kCentre | kLRPair:
132 case kVhlVhrPair | kTopCentre | kTopfrontCentre | kLFE | kTblTbrPair |
133 kLsRsPair | kCentre | kLRPair:
134 ret = 17;
135 break;
136 case kTopCentre | kTopfrontCentre | kLFE | kTblTbrPair | kTflTfrPair |
137 kCentre | kLRPair | kLsRsPair | kLbRbPair:
138 case kVhlVhrPair | kTopCentre | kTopfrontCentre | kLFE | kTblTbrPair |
139 kCentre | kLRPair | kLsRsPair | kLbRbPair:
140 ret = 18;
141 break;
142 case kLFE | kTblTbrPair | kTflTfrPair | kCentre | kLRPair | kLsRsPair |
143 kLbRbPair:
144 case kVhlVhrPair | kLFE | kTblTbrPair | kCentre | kLRPair | kLsRsPair |
145 kLbRbPair:
146 ret = 19;
147 break;
148 case kLscrRscrPair | kLFE | kTblTbrPair | kTflTfrPair | kCentre | kLRPair |
149 kLsRsPair | kLbRbPair:
150 case kVhlVhrPair | kLscrRscrPair | kLFE | kTblTbrPair | kCentre | kLRPair |
151 kLsRsPair | kLbRbPair:
152 ret = 20;
153 break;
154 default:
155 ret = 0xFFFFFFFF;
156 }
157 return ret;
158}
159
160// Parse AC-4 substream group based on ETSI TS 103 192-2 V1.2.1 Digital Audio
161// Compression (AC-4) Standard; Part 2: Immersive and personalized E.11.
162bool ParseAC4SubStreamGroupDsi(BitReader& bit_reader) {
163 bool b_substream_present;
164 RCHECK(bit_reader.ReadBits(1, &b_substream_present));
165 bool b_hsf_ext;
166 RCHECK(bit_reader.ReadBits(1, &b_hsf_ext));
167 bool b_channel_coded;
168 RCHECK(bit_reader.ReadBits(1, &b_channel_coded));
169 uint8_t n_substreams;
170 RCHECK(bit_reader.ReadBits(8, &n_substreams));
171 for (uint8_t i = 0; i < n_substreams; i++) {
172 RCHECK(bit_reader.SkipBits(2));
173 bool b_substream_bitrate_indicator;
174 RCHECK(bit_reader.ReadBits(1, &b_substream_bitrate_indicator));
175 if (b_substream_bitrate_indicator) {
176 RCHECK(bit_reader.SkipBits(5));
177 }
178 if (b_channel_coded) {
179 RCHECK(bit_reader.SkipBits(24));
180 } else {
181 bool b_ajoc;
182 RCHECK(bit_reader.ReadBits(1, &b_ajoc));
183 if (b_ajoc) {
184 bool b_static_dmx;
185 RCHECK(bit_reader.ReadBits(1, &b_static_dmx));
186 if (!b_static_dmx) {
187 RCHECK(bit_reader.SkipBits(4));
188 }
189 RCHECK(bit_reader.SkipBits(6));
190 }
191 RCHECK(bit_reader.SkipBits(4));
192 }
193 }
194 bool b_content_type;
195 RCHECK(bit_reader.ReadBits(1, &b_content_type));
196 if (b_content_type) {
197 RCHECK(bit_reader.SkipBits(3));
198 bool b_language_indicator;
199 RCHECK(bit_reader.ReadBits(1, &b_language_indicator));
200 if (b_language_indicator) {
201 uint8_t n_language_tag_bytes;
202 RCHECK(bit_reader.ReadBits(6, &n_language_tag_bytes));
203 RCHECK(bit_reader.SkipBits(n_language_tag_bytes * 8));
204 }
205 }
206 return true;
207}
208
209// Parse AC-4 Presentation V1 based on ETSI TS 103 192-2 V1.2.1 Digital Audio
210// Compression (AC-4) Standard;Part 2: Immersive and personalized E.10.
211bool ParseAC4PresentationV1Dsi(BitReader& bit_reader,
212 uint32_t pres_bytes,
213 uint8_t* mdcompat,
214 uint32_t* presentation_channel_mask_v1,
215 bool* dolby_cbi_indicator,
216 uint8_t* dolby_atmos_indicator) {
217 bool ret = true;
218 // Record the initial offset.
219 const size_t presentation_start = bit_reader.bit_position();
220 uint8_t presentation_config_v1;
221 RCHECK(bit_reader.ReadBits(5, &presentation_config_v1));
222 uint8_t b_add_emdf_substreams;
223 // set default value (stereo content) for output parameters.
224 *mdcompat = 0;
225 *presentation_channel_mask_v1 = 2;
226 *dolby_cbi_indicator = false;
227 *dolby_atmos_indicator = 0;
228 if (presentation_config_v1 == 0x06) {
229 b_add_emdf_substreams = 1;
230 } else {
231 RCHECK(bit_reader.ReadBits(3, mdcompat));
232 bool b_presentation_id;
233 RCHECK(bit_reader.ReadBits(1, &b_presentation_id));
234 if (b_presentation_id) {
235 RCHECK(bit_reader.SkipBits(5));
236 }
237 RCHECK(bit_reader.SkipBits(19));
238 bool b_presentation_channel_coded;
239 RCHECK(bit_reader.ReadBits(1, &b_presentation_channel_coded));
240 *presentation_channel_mask_v1 = 0;
241 if (b_presentation_channel_coded) {
242 uint8_t dsi_presentation_ch_mode;
243 RCHECK(bit_reader.ReadBits(5, &dsi_presentation_ch_mode));
244 if (dsi_presentation_ch_mode >= 11 && dsi_presentation_ch_mode <= 14) {
245 RCHECK(bit_reader.SkipBits(1));
246 uint8_t pres_top_channel_pairs;
247 RCHECK(bit_reader.ReadBits(2, &pres_top_channel_pairs));
248 if (pres_top_channel_pairs) {
249 *dolby_cbi_indicator = true;
250 }
251 } else if (dsi_presentation_ch_mode == 15) {
252 *dolby_cbi_indicator = true;
253 }
254 RCHECK(bit_reader.ReadBits(24, presentation_channel_mask_v1));
255 }
256 bool b_presentation_core_differs;
257 RCHECK(bit_reader.ReadBits(1, &b_presentation_core_differs));
258 if (b_presentation_core_differs) {
259 bool b_presentation_core_channel_coded;
260 RCHECK(bit_reader.ReadBits(1, &b_presentation_core_channel_coded));
261 if (b_presentation_core_channel_coded) {
262 RCHECK(bit_reader.SkipBits(2));
263 }
264 }
265 bool b_presentation_filter;
266 RCHECK(bit_reader.ReadBits(1, &b_presentation_filter));
267 if (b_presentation_filter) {
268 RCHECK(bit_reader.SkipBits(1));
269 uint8_t n_filter_bytes;
270 RCHECK(bit_reader.ReadBits(8, &n_filter_bytes));
271 RCHECK(bit_reader.SkipBits(n_filter_bytes * 8));
272 }
273 if (presentation_config_v1 == 0x1f) {
274 ret &= ParseAC4SubStreamGroupDsi(bit_reader);
275 } else {
276 RCHECK(bit_reader.SkipBits(1));
277 if (presentation_config_v1 == 0 || presentation_config_v1 == 1 ||
278 presentation_config_v1 == 2) {
279 ret &= ParseAC4SubStreamGroupDsi(bit_reader);
280 ret &= ParseAC4SubStreamGroupDsi(bit_reader);
281 }
282 if (presentation_config_v1 == 3 || presentation_config_v1 == 4) {
283 ret &= ParseAC4SubStreamGroupDsi(bit_reader);
284 ret &= ParseAC4SubStreamGroupDsi(bit_reader);
285 ret &= ParseAC4SubStreamGroupDsi(bit_reader);
286 }
287 if (presentation_config_v1 == 5) {
288 uint8_t n_substream_groups_minus2;
289 RCHECK(bit_reader.ReadBits(3, &n_substream_groups_minus2));
290 for (uint8_t sg = 0; sg < n_substream_groups_minus2 + 2; sg++) {
291 ret &= ParseAC4SubStreamGroupDsi(bit_reader);
292 }
293 }
294 if (presentation_config_v1 > 5) {
295 uint8_t n_skip_bytes;
296 RCHECK(bit_reader.ReadBits(7, &n_skip_bytes));
297 RCHECK(bit_reader.SkipBits(n_skip_bytes * 8));
298 }
299 }
300 RCHECK(bit_reader.SkipBits(1));
301 RCHECK(bit_reader.ReadBits(1, &b_add_emdf_substreams));
302 }
303 if (b_add_emdf_substreams) {
304 uint8_t n_add_emdf_substreams;
305 RCHECK(bit_reader.ReadBits(7, &n_add_emdf_substreams));
306 RCHECK(bit_reader.SkipBits(n_add_emdf_substreams * 15));
307 }
308 bool b_presentation_bitrate_info;
309 RCHECK(bit_reader.ReadBits(1, &b_presentation_bitrate_info));
310 if (b_presentation_bitrate_info) {
311 // Skip bit rate information based on ETSI TS 103 190-2 v1.2.1 E.7.1
312 RCHECK(bit_reader.SkipBits(66));
313 }
314 bool b_alternative;
315 RCHECK(bit_reader.ReadBits(1, &b_alternative));
316 if (b_alternative) {
317 bit_reader.SkipToNextByte();
318 // Parse alternative information based on ETSI TS 103 190-2 v1.2.1 E.12
319 uint16_t name_len;
320 RCHECK(bit_reader.ReadBits(16, &name_len));
321 RCHECK(bit_reader.SkipBits(name_len * 8));
322 uint8_t n_targets;
323 RCHECK(bit_reader.ReadBits(5, &n_targets));
324 RCHECK(bit_reader.SkipBits(n_targets * 11));
325 }
326 bit_reader.SkipToNextByte();
327 if ((bit_reader.bit_position() - presentation_start) <=
328 (pres_bytes - 1) * 8) {
329 RCHECK(bit_reader.SkipBits(1));
330 RCHECK(bit_reader.ReadBits(1, dolby_atmos_indicator));
331 RCHECK(bit_reader.SkipBits(4));
332 bool b_extended_presentation_group_index;
333 RCHECK(bit_reader.ReadBits(1, &b_extended_presentation_group_index));
334 if (b_extended_presentation_group_index) {
335 RCHECK(bit_reader.SkipBits(9));
336 } else {
337 RCHECK(bit_reader.SkipBits(1));
338 }
339 }
340 return ret;
341}
342
343bool ExtractAc4Data(const std::vector<uint8_t>& ac4_data,
344 uint8_t* bitstream_version,
345 uint8_t* presentation_version,
346 uint8_t* mdcompat,
347 uint32_t* presentation_channel_mask_v1,
348 bool* dolby_ims_indicator,
349 bool* dolby_cbi_indicator) {
350 BitReader bit_reader(ac4_data.data(), ac4_data.size());
351
352 uint16_t n_presentation;
353 RCHECK(bit_reader.SkipBits(3) && bit_reader.ReadBits(7, bitstream_version));
354 RCHECK(bit_reader.SkipBits(5) && bit_reader.ReadBits(9, &n_presentation));
355
356 if (*bitstream_version == 2) {
357 uint8_t b_program_id = 0;
358 RCHECK(bit_reader.ReadBits(1, &b_program_id));
359 if (b_program_id) {
360 RCHECK(bit_reader.SkipBits(16));
361 uint8_t b_uuid = 0;
362 RCHECK(bit_reader.ReadBits(1, &b_uuid));
363 if (b_uuid) {
364 RCHECK(bit_reader.SkipBits(16 * 8));
365 }
366 }
367 } else if (*bitstream_version == 0 || *bitstream_version == 1) {
368 LOG(WARNING) << "Bitstream version 0 or 1 is not supported";
369 return false;
370 } else {
371 LOG(WARNING) << "Invalid Bitstream version";
372 return false;
373 }
374
375 RCHECK(bit_reader.SkipBits(66));
376 bit_reader.SkipToNextByte();
377
378 // AC4 stream containing the single presentation is valid for OTT only.
379 // IMS has two presentations, and the 2nd is legacy (duplicated) presentation.
380 // So it can be considered as AC4 stream with single presentation. And IMS
381 // presentation must be prior to legacy presentation.
382 // In other word, only the 1st presentation in AC4 stream need to be parsed.
383 const uint8_t ott_n_presentation = 1;
384 for (uint8_t i = 0; i < ott_n_presentation; i++) {
385 RCHECK(bit_reader.ReadBits(8, presentation_version));
386 // *presentation_version == 2 means IMS presentation.
387 if ((*presentation_version == 2 && n_presentation > 2) ||
388 (*presentation_version == 1 && n_presentation > 1)) {
389 LOG(WARNING) << "Seeing multiple presentations, only single presentation "
390 << "(including IMS presentation) is supported";
391 return false;
392 }
393 uint32_t pres_bytes;
394 RCHECK(bit_reader.ReadBits(8, &pres_bytes));
395 if (pres_bytes == 255) {
396 uint32_t add_pres_bytes;
397 RCHECK(bit_reader.ReadBits(16, &add_pres_bytes));
398 pres_bytes += add_pres_bytes;
399 }
400
401 size_t presentation_bits = 0;
402 *dolby_ims_indicator = false;
403 if (*presentation_version == 0) {
404 LOG(WARNING) << "Presentation version 0 is not supported";
405 return false;
406 } else {
407 if (*presentation_version == 1 || *presentation_version == 2) {
408 if (*presentation_version == 2) {
409 *dolby_ims_indicator = true;
410 }
411 const size_t presentation_start = bit_reader.bit_position();
412 // dolby_atmos_indicator is extended in Dolby internal specs.
413 // It indicates whether the source content before encoding is Atmos.
414 // No final decision about how to use it in OTT.
415 // Parse it for the future usage.
416 uint8_t dolby_atmos_indicator;
417 if (!ParseAC4PresentationV1Dsi(
418 bit_reader, pres_bytes, mdcompat, presentation_channel_mask_v1,
419 dolby_cbi_indicator, &dolby_atmos_indicator)) {
420 return false;
421 }
422 const size_t presentation_end = bit_reader.bit_position();
423 presentation_bits = presentation_end - presentation_start;
424 } else {
425 LOG(WARNING) << "Invalid Presentation version";
426 return false;
427 }
428 }
429 size_t skip_bits = pres_bytes * 8 - presentation_bits;
430 RCHECK(bit_reader.SkipBits(skip_bits));
431 }
432 return true;
433}
434} // namespace
435
436bool CalculateAC4ChannelMask(const std::vector<uint8_t>& ac4_data,
437 uint32_t* ac4_channel_mask) {
438 uint8_t bitstream_version;
439 uint8_t presentation_version;
440 uint8_t mdcompat;
441 uint32_t pre_channel_mask;
442 bool dolby_ims_indicator;
443 bool dolby_cbi_indicator;
444
445 if (!ExtractAc4Data(ac4_data, &bitstream_version, &presentation_version,
446 &mdcompat, &pre_channel_mask, &dolby_ims_indicator,
447 &dolby_cbi_indicator)) {
448 LOG(WARNING) << "Seeing invalid AC4 data: "
449 << absl::BytesToHexString(
451 return false;
452 }
453
454 if (pre_channel_mask) {
455 *ac4_channel_mask = pre_channel_mask;
456 } else {
457 *ac4_channel_mask = 0x800000;
458 }
459 return true;
460}
461
462bool CalculateAC4ChannelMPEGValue(const std::vector<uint8_t>& ac4_data,
463 uint32_t* ac4_channel_mpeg_value) {
464 uint8_t bitstream_version;
465 uint8_t presentation_version;
466 uint8_t mdcompat;
467 uint32_t pre_channel_mask;
468 bool dolby_ims_indicator;
469 bool dolby_cbi_indicator;
470
471 if (!ExtractAc4Data(ac4_data, &bitstream_version, &presentation_version,
472 &mdcompat, &pre_channel_mask, &dolby_ims_indicator,
473 &dolby_cbi_indicator)) {
474 LOG(WARNING) << "Seeing invalid AC4 data: "
475 << absl::BytesToHexString(
477 return false;
478 }
479
480 *ac4_channel_mpeg_value = AC4ChannelMasktoMPEGValue(pre_channel_mask);
481 return true;
482}
483
484bool GetAc4CodecInfo(const std::vector<uint8_t>& ac4_data,
485 uint8_t* ac4_codec_info) {
486 uint8_t bitstream_version;
487 uint8_t presentation_version;
488 uint8_t mdcompat;
489 uint32_t pre_channel_mask;
490 bool dolby_ims_indicator;
491 bool dolby_cbi_indicator;
492
493 if (!ExtractAc4Data(ac4_data, &bitstream_version, &presentation_version,
494 &mdcompat, &pre_channel_mask, &dolby_ims_indicator,
495 &dolby_cbi_indicator)) {
496 LOG(WARNING) << "Seeing invalid AC4 data: "
497 << absl::BytesToHexString(
499 return false;
500 }
501
502 // The valid value of bitstream_version (8 bits) is 2, the valid value of
503 // presentation_version (8 bits) is 1 or 2, and mdcompat is 3 bits.
504 // So uint8_t is fine now. If Dolby extends the value of bitstream_version and
505 // presentation_version in future, maybe need change the type from uint8_t to
506 // uint16_t or uint32_t to accommodate the valid values.
507 // If that, AudioStreamInfo::GetCodecString need to be changed accordingly.
508 // bitstream_version (3bits) + presentation_version (2bits) + mdcompat (3bits)
509 *ac4_codec_info = ((bitstream_version << 5) |
510 ((presentation_version << 3) & 0x1F) | (mdcompat & 0x7));
511 return true;
512}
513
514bool GetAc4ImmersiveInfo(const std::vector<uint8_t>& ac4_data,
515 bool* ac4_ims_flag,
516 bool* ac4_cbi_flag) {
517 uint8_t bitstream_version;
518 uint8_t presentation_version;
519 uint8_t mdcompat;
520 uint32_t pre_channel_mask;
521
522 if (!ExtractAc4Data(ac4_data, &bitstream_version, &presentation_version,
523 &mdcompat, &pre_channel_mask, ac4_ims_flag,
524 ac4_cbi_flag)) {
525 LOG(WARNING) << "Seeing invalid AC4 data: "
526 << absl::BytesToHexString(
528 return false;
529 }
530
531 return true;
532}
533
534} // namespace media
535} // namespace shaka
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.