1 /*
2 mkvmerge -- utility for splicing together matroska files
3 from component media subtypes
4
5 Distributed under the GPL v2
6 see the file COPYING for details
7 or visit https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
8
9 helper function for AC-3 data
10
11 Written by Moritz Bunkus <moritz@bunkus.org>.
12 */
13
14 #include "common/common_pch.h"
15
16 #include <cstring>
17
18 #include "common/ac3.h"
19 #include "common/bit_reader.h"
20 #include "common/bit_writer.h"
21 #include "common/bswap.h"
22 #include "common/byte_buffer.h"
23 #include "common/channels.h"
24 #include "common/checksums/base.h"
25 #include "common/codec.h"
26 #include "common/debugging.h"
27 #include "common/endian.h"
28 #include "common/math.h"
29 #include "common/strings/formatting.h"
30
31 namespace mtx::ac3 {
32
33 namespace {
34 uint64_t s_acmod_to_channel_layout[8] = {
35 mtx::channels::front_left | mtx::channels::front_right,
36 mtx::channels::front_center,
37 mtx::channels::front_left | mtx::channels::front_right,
38 mtx::channels::front_left | mtx::channels::front_right | mtx::channels::front_center,
39 mtx::channels::front_left | mtx::channels::front_right | mtx::channels::back_center,
40 mtx::channels::front_left | mtx::channels::front_right | mtx::channels::front_center | mtx::channels::back_center,
41 mtx::channels::front_left | mtx::channels::front_right | mtx::channels::side_left | mtx::channels::side_right,
42 mtx::channels::front_left | mtx::channels::front_right | mtx::channels::front_center | mtx::channels::side_left | mtx::channels::side_right,
43 };
44
45 uint64_t s_custom_channel_map_to_layout[16] = {
46 mtx::channels::front_left,
47 mtx::channels::front_center,
48 mtx::channels::front_right,
49 mtx::channels::side_left,
50 mtx::channels::side_right,
51 mtx::channels::front_left_of_center | mtx::channels::front_right_of_center,
52 mtx::channels::back_left | mtx::channels::back_right,
53 mtx::channels::back_center,
54 mtx::channels::top_center,
55 mtx::channels::surround_direct_left | mtx::channels::surround_direct_right,
56 mtx::channels::wide_left | mtx::channels::wide_right,
57 mtx::channels::top_front_left | mtx::channels::top_front_right,
58 mtx::channels::top_front_center,
59 mtx::channels::top_back_left | mtx::channels::top_back_right,
60 mtx::channels::low_frequency_2,
61 mtx::channels::low_frequency,
62 };
63
64 }
65
66 void
init()67 frame_c::init() {
68 *this = frame_c{};
69 }
70
71 bool
is_eac3() const72 frame_c::is_eac3()
73 const {
74 return ((10 < m_bs_id) && (16 >= m_bs_id)) || !m_dependent_frames.empty();
75 }
76
77 codec_c
get_codec() const78 frame_c::get_codec()
79 const {
80 auto specialization = is_eac3() ? codec_c::specialization_e::e_ac_3
81 : m_is_surround_ex ? codec_c::specialization_e::ac3_dolby_surround_ex
82 : codec_c::specialization_e::none;
83
84 return codec_c::look_up(codec_c::type_e::A_AC3).specialize(specialization);
85 }
86
87 void
add_dependent_frame(frame_c const & frame,unsigned char const * buffer,std::size_t buffer_size)88 frame_c::add_dependent_frame(frame_c const &frame,
89 unsigned char const *buffer,
90 std::size_t buffer_size) {
91 m_data->add(buffer, buffer_size);
92 m_dependent_frames.push_back(frame);
93
94 m_channels = get_effective_number_of_channels();
95 }
96
97 bool
decode_header(unsigned char const * buffer,std::size_t buffer_size)98 frame_c::decode_header(unsigned char const *buffer,
99 std::size_t buffer_size) {
100 if (buffer_size < 18)
101 return false;
102
103 unsigned char swapped_buffer[18];
104 std::unique_ptr<mtx::bits::reader_c> r;
105
106 if (get_uint16_le(buffer) == SYNC_WORD) {
107 // byte-swapped
108 mtx::bytes::swap_buffer(buffer, swapped_buffer, 18, 2);
109 r.reset(new mtx::bits::reader_c(swapped_buffer, 18));
110
111 } else if (get_uint16_be(buffer) == SYNC_WORD)
112 r.reset(new mtx::bits::reader_c(buffer, 18));
113
114 else
115 return false;
116
117 try {
118 init();
119
120 r->set_bit_position(16);
121 m_bs_id = r->get_bits(29) & 0x1f;
122 r->set_bit_position(16);
123
124 m_valid = 16 == m_bs_id ? decode_header_type_eac3(*r) // original E-AC-3
125 : 8 >= m_bs_id ? decode_header_type_ac3(*r) // regular AC-3
126 : (16 > m_bs_id) && (10 < m_bs_id) ? decode_header_type_eac3(*r) // versions of E-AC-3 backwards-compatible with 0x10
127 : false;
128
129 } catch (mtx::mm_io::end_of_file_x &) {
130 }
131
132 return m_valid;
133 }
134
135 bool
decode_header_type_eac3(mtx::bits::reader_c & bc)136 frame_c::decode_header_type_eac3(mtx::bits::reader_c &bc) {
137 static const int sample_rates[] = { 48000, 44100, 32000, 24000, 22050, 16000 };
138 static const int samples[] = { 256, 512, 768, 1536 };
139
140 m_frame_type = bc.get_bits(2);
141
142 if (FRAME_TYPE_RESERVED == m_frame_type)
143 return false;
144
145 m_sub_stream_id = bc.get_bits(3);
146 m_bytes = (bc.get_bits(11) + 1) << 1;
147
148 if (!m_bytes)
149 return false;
150
151 uint8_t fscod = bc.get_bits(2);
152 uint8_t fscod2 = bc.get_bits(2);
153
154 if ((0x03 == fscod) && (0x03 == fscod2))
155 return false;
156
157 uint8_t acmod = bc.get_bits(3);
158 uint8_t lfeon = bc.get_bit();
159 bc.skip_bits(5); // bsid
160
161 m_dialog_normalization_gain_bit_position = bc.get_bit_position();
162 m_dialog_normalization_gain = bc.get_bits(5);
163
164 if (bc.get_bit()) // compre
165 bc.skip_bits(8); // compr
166
167 if (acmod == 0x00) { // dual mono mode
168 m_dialog_normalization_gain2_bit_position = bc.get_bit_position();
169 m_dialog_normalization_gain2 = bc.get_bits(5);
170
171 if (bc.get_bit()) // compr2e
172 bc.skip_bits(8); // compr2
173 }
174
175 if ((m_frame_type == FRAME_TYPE_DEPENDENT) && bc.get_bit()) { // chanmape
176 auto chanmap = bc.get_bits(16);
177 m_channel_layout = 0;
178
179 for (auto idx = 0; idx < 16; ++idx) {
180 auto mask = 1 << (15 - idx);
181 if (chanmap & mask)
182 m_channel_layout |= s_custom_channel_map_to_layout[idx];
183 }
184
185 } else
186 m_channel_layout = s_acmod_to_channel_layout[acmod];
187
188 m_sample_rate = sample_rates[0x03 == fscod ? 3 + fscod2 : fscod];
189 m_lfeon = lfeon;
190 m_samples = (0x03 == fscod) ? 1536 : samples[fscod2];
191 m_channels = get_effective_number_of_channels();
192
193 return true;
194 }
195
196 bool
decode_header_type_ac3(mtx::bits::reader_c & bc)197 frame_c::decode_header_type_ac3(mtx::bits::reader_c &bc) {
198 static const uint16_t sample_rates[] = { 48000, 44100, 32000 };
199 static const uint16_t bit_rates[] = { 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 576, 640 };
200 static const uint16_t frame_sizes[38][3] = {
201 { 64, 69, 96 },
202 { 64, 70, 96 },
203 { 80, 87, 120 },
204 { 80, 88, 120 },
205 { 96, 104, 144 },
206 { 96, 105, 144 },
207 { 112, 121, 168 },
208 { 112, 122, 168 },
209 { 128, 139, 192 },
210 { 128, 140, 192 },
211 { 160, 174, 240 },
212 { 160, 175, 240 },
213 { 192, 208, 288 },
214 { 192, 209, 288 },
215 { 224, 243, 336 },
216 { 224, 244, 336 },
217 { 256, 278, 384 },
218 { 256, 279, 384 },
219 { 320, 348, 480 },
220 { 320, 349, 480 },
221 { 384, 417, 576 },
222 { 384, 418, 576 },
223 { 448, 487, 672 },
224 { 448, 488, 672 },
225 { 512, 557, 768 },
226 { 512, 558, 768 },
227 { 640, 696, 960 },
228 { 640, 697, 960 },
229 { 768, 835, 1152 },
230 { 768, 836, 1152 },
231 { 896, 975, 1344 },
232 { 896, 976, 1344 },
233 { 1024, 1114, 1536 },
234 { 1024, 1115, 1536 },
235 { 1152, 1253, 1728 },
236 { 1152, 1254, 1728 },
237 { 1280, 1393, 1920 },
238 { 1280, 1394, 1920 },
239 };
240
241 bc.skip_bits(16); // crc1
242 uint8_t fscod = bc.get_bits(2);
243 if (0x03 == fscod)
244 return false;
245
246 uint8_t frmsizecod = bc.get_bits(6);
247 if (38 <= frmsizecod)
248 return false;
249
250 auto bsid = bc.get_bits(5); // bsid
251 bc.skip_bits(3); // bsmod
252
253 uint8_t acmod = bc.get_bits(3);
254
255 if ((acmod & 0x01) && (acmod != 0x01))
256 bc.skip_bits(2); // cmixlev
257 if (acmod & 0x04)
258 bc.skip_bits(2); // surmixlev
259 if (0x02 == acmod)
260 bc.skip_bits(2); // dsurmod
261 uint8_t lfeon = bc.get_bit();
262
263 uint8_t sr_shift = std::max(m_bs_id, 8u) - 8;
264
265 m_dialog_normalization_gain_bit_position = bc.get_bit_position();
266 m_dialog_normalization_gain = bc.get_bits(5);
267 m_sample_rate = sample_rates[fscod] >> sr_shift;
268 m_bit_rate = (bit_rates[frmsizecod >> 1] * 1000) >> sr_shift;
269 m_lfeon = lfeon;
270 m_channel_layout = s_acmod_to_channel_layout[acmod];
271 m_channels = get_effective_number_of_channels();
272 m_bytes = frame_sizes[frmsizecod][fscod] << 1;
273
274 m_samples = 1536;
275 m_frame_type = FRAME_TYPE_INDEPENDENT;
276
277 if (bc.get_bit()) // compre
278 bc.skip_bits(8); // compr
279 if (bc.get_bit()) // langcode
280 bc.skip_bits(8); // langcod
281 if (bc.get_bit()) // audprodie
282 bc.skip_bits(5 + 2); // mixlevel, roomtyp
283
284 if (acmod == 0) {
285 // Dual-mono mode
286 m_dialog_normalization_gain2_bit_position = bc.get_bit_position();
287 m_dialog_normalization_gain2 = bc.get_bits(5);
288
289 if (bc.get_bit()) // compre2
290 bc.skip_bits(8); // compr2
291 if (bc.get_bit()) // langcode2
292 bc.skip_bits(8); // langcod2
293 if (bc.get_bit()) // audprodie2
294 bc.skip_bits(5 + 2); // mixlevel2, roomtyp2
295 }
296
297 bc.skip_bits(2); // copyrightb, origbs
298
299 if (bsid == 6) {
300 // Alternate Bit Syntax Stream
301
302 if (bc.get_bit()) // xbsi1e
303 bc.skip_bits( 2 + 3 + 3 // dmixmod, ltrtcmixlev, ltrtsurmixlev
304 + 3 + 3); // lorocmixlev, lorosurmixlev
305
306 if (bc.get_bit()) { // xbsi2e
307 auto dsurexmod = bc.get_bits(2);
308 m_is_surround_ex = dsurexmod == 0b10;
309 }
310 }
311
312 return m_bytes != 0;
313 }
314
315 int
find_in(memory_cptr const & buffer)316 frame_c::find_in(memory_cptr const &buffer) {
317 return find_in(buffer->get_buffer(), buffer->get_size());
318 }
319
320 int
find_in(unsigned char const * buffer,std::size_t buffer_size)321 frame_c::find_in(unsigned char const *buffer,
322 std::size_t buffer_size) {
323 for (int offset = 0; offset < static_cast<int>(buffer_size); ++offset)
324 if (decode_header(&buffer[offset], buffer_size - offset))
325 return offset;
326 return -1;
327 }
328
329 uint64_t
get_effective_channel_layout() const330 frame_c::get_effective_channel_layout()
331 const {
332 auto channel_layout = m_channel_layout;
333
334 for (auto const &dependent_frame : m_dependent_frames)
335 channel_layout |= dependent_frame.m_channel_layout;
336
337 return channel_layout;
338 }
339
340 int
get_effective_number_of_channels() const341 frame_c::get_effective_number_of_channels()
342 const {
343 auto num_channels = mtx::math::count_1_bits(get_effective_channel_layout()) + (m_lfeon ? 1 : 0);
344 for (auto const &dependent_frame : m_dependent_frames)
345 if (dependent_frame.m_lfeon)
346 ++num_channels;
347
348 return num_channels;
349 }
350
351 std::string
to_string(bool verbose) const352 frame_c::to_string(bool verbose)
353 const {
354 if (!verbose)
355 return fmt::format("position {0} BS ID {1} size {2} E-AC-3 {3}", m_stream_position, m_bs_id, m_bytes, is_eac3());
356
357 const std::string &frame_type = !is_eac3() ? "---"
358 : m_frame_type == FRAME_TYPE_INDEPENDENT ? "independent"
359 : m_frame_type == FRAME_TYPE_DEPENDENT ? "dependent"
360 : m_frame_type == FRAME_TYPE_AC3_CONVERT ? "AC-3 convert"
361 : m_frame_type == FRAME_TYPE_RESERVED ? "reserved"
362 : "unknown";
363
364 auto output = fmt::format("position {0} size {2} garbage {1} BS ID {3} E-AC-3 {14} sample rate {4} bit rate {5} channels {6} (effective layout 0x{15:08x}) flags {7} samples {8} type {9} ({12}) "
365 "sub stream ID {10} has dependent frames {11} total size {13}",
366 m_stream_position,
367 m_garbage_size,
368 m_bytes,
369 m_bs_id,
370 m_sample_rate,
371 m_bit_rate,
372 m_channels,
373 m_flags,
374 m_samples,
375 m_frame_type,
376 m_sub_stream_id,
377 m_dependent_frames.size(),
378 frame_type,
379 m_data ? m_data->get_size() : 0,
380 is_eac3(),
381 get_effective_channel_layout());
382
383 for (auto &frame : m_dependent_frames)
384 output += fmt::format(" { {0} }", frame.to_string(verbose));
385
386 return output;
387 }
388
389 // ------------------------------------------------------------
390
parser_c()391 parser_c::parser_c()
392 : m_parsed_stream_position(0)
393 , m_total_stream_position(0)
394 , m_garbage_size(0)
395 {
396 }
397
398 void
add_bytes(memory_cptr const & mem)399 parser_c::add_bytes(memory_cptr const &mem) {
400 add_bytes(mem->get_buffer(), mem->get_size());
401 }
402
403 void
add_bytes(unsigned char * const buffer,std::size_t size)404 parser_c::add_bytes(unsigned char *const buffer,
405 std::size_t size) {
406 m_buffer.add(buffer, size);
407 m_total_stream_position += size;
408 parse(false);
409 }
410
411 void
flush()412 parser_c::flush() {
413 parse(true);
414 }
415
416 std::size_t
frame_available() const417 parser_c::frame_available()
418 const {
419 return m_frames.size();
420 }
421
422 frame_c
get_frame()423 parser_c::get_frame() {
424 frame_c frame = m_frames.front();
425 m_frames.pop_front();
426 return frame;
427 }
428
429 uint64_t
get_total_stream_position() const430 parser_c::get_total_stream_position()
431 const {
432 return m_total_stream_position;
433 }
434
435 uint64_t
get_parsed_stream_position() const436 parser_c::get_parsed_stream_position()
437 const {
438 return m_parsed_stream_position;
439 }
440
441 void
parse(bool end_of_stream)442 parser_c::parse(bool end_of_stream) {
443 unsigned char swapped_buffer[18];
444 unsigned char *const buffer = m_buffer.get_buffer();
445 std::size_t buffer_size = m_buffer.get_size();
446 std::size_t position = 0;
447
448 while ((position + 18) < buffer_size) {
449 frame_c frame;
450 unsigned char const *buffer_to_decode;
451
452 if (get_uint16_le(&buffer[position]) == SYNC_WORD) {
453 mtx::bytes::swap_buffer(&buffer[position], swapped_buffer, 18, 2);
454 buffer_to_decode = swapped_buffer;
455
456 } else
457 buffer_to_decode = &buffer[position];
458
459 if (!frame.decode_header(buffer_to_decode, 18)) {
460 ++position;
461 ++m_garbage_size;
462 continue;
463 }
464
465 if ((position + frame.m_bytes) > buffer_size)
466 break;
467
468 if (buffer_to_decode == swapped_buffer)
469 mtx::bytes::swap_buffer(&buffer[position], &buffer[position], frame.m_bytes, 2);
470
471 frame.m_stream_position = m_parsed_stream_position + position;
472
473 if (!m_current_frame.m_valid || (FRAME_TYPE_DEPENDENT != frame.m_frame_type)) {
474 if (m_current_frame.m_valid)
475 m_frames.push_back(m_current_frame);
476
477 m_current_frame = frame;
478 m_current_frame.m_data = memory_c::clone(&buffer[position], frame.m_bytes);
479
480 } else
481 m_current_frame.add_dependent_frame(frame, &buffer[position], frame.m_bytes);
482
483 m_current_frame.m_garbage_size += m_garbage_size;
484 m_garbage_size = 0;
485 position += frame.m_bytes;
486 }
487
488 m_buffer.remove(position);
489 m_parsed_stream_position += position;
490
491 if (m_current_frame.m_valid && end_of_stream) {
492 m_frames.push_back(m_current_frame);
493 m_current_frame.init();
494 }
495 }
496
497 int
find_consecutive_frames(unsigned char const * buffer,std::size_t buffer_size,std::size_t num_required_headers)498 parser_c::find_consecutive_frames(unsigned char const *buffer,
499 std::size_t buffer_size,
500 std::size_t num_required_headers) {
501 static auto s_debug = debugging_option_c{"ac3_consecutive_frames"};
502 std::size_t base = 0;
503
504 do {
505 mxdebug_if(s_debug, fmt::format("Starting search for {1} headers with base {0}, buffer size {2}\n", base, num_required_headers, buffer_size));
506
507 std::size_t position = base;
508
509 frame_c first_frame;
510 while (((position + 8) < buffer_size) && !first_frame.decode_header(&buffer[position], buffer_size - position))
511 ++position;
512
513 mxdebug_if(s_debug, fmt::format("First frame at {0} valid {1}\n", position, first_frame.m_valid));
514
515 if (!first_frame.m_valid)
516 return -1;
517
518 std::size_t offset = position + first_frame.m_bytes;
519 std::size_t num_headers_found = 1;
520
521 while ( (num_headers_found < num_required_headers)
522 && (offset < buffer_size)) {
523
524 frame_c current_frame;
525 if (!current_frame.decode_header(&buffer[offset], buffer_size - offset))
526 break;
527
528 if (8 > current_frame.m_bytes) {
529 mxdebug_if(s_debug, fmt::format("Current frame at {0} has invalid size {1}\n", offset, current_frame.m_bytes));
530 break;
531 }
532
533 if ( (current_frame.m_bs_id != first_frame.m_bs_id)
534 && (current_frame.m_channels != first_frame.m_channels)
535 && (current_frame.m_sample_rate != first_frame.m_sample_rate)) {
536 mxdebug_if(s_debug,
537 fmt::format("Current frame at {6} differs from first frame. (first/current) BS ID: {0}/{1} channels: {2}/{3} sample rate: {4}/{5}\n",
538 first_frame.m_bs_id, current_frame.m_bs_id, first_frame.m_channels, current_frame.m_channels, first_frame.m_sample_rate, current_frame.m_sample_rate, offset));
539 break;
540 }
541
542 mxdebug_if(s_debug, fmt::format("Current frame at {0} equals first frame, found {1}\n", offset, num_headers_found + 1));
543
544 ++num_headers_found;
545 offset += current_frame.m_bytes;
546 }
547
548 if (num_headers_found == num_required_headers) {
549 mxdebug_if(s_debug, fmt::format("Found required number of headers at {0}\n", position));
550 return position;
551 }
552
553 base = position + 2;
554 } while (base < buffer_size);
555
556 return -1;
557 }
558
559 // ------------------------------------------------------------
560
561 /*
562 The functions mul_poly, pow_poly and verify_ac3_crc were taken
563 or adopted from the ffmpeg project, file "libavcodec/ac3enc.c".
564
565 The license here is the GPL v2.
566 */
567
568 constexpr auto CRC16_POLY = (1 << 0) | (1 << 2) | (1 << 15) | (1 << 16);
569
570 static unsigned int
mul_poly(unsigned int a,unsigned int b,unsigned int poly)571 mul_poly(unsigned int a,
572 unsigned int b,
573 unsigned int poly) {
574 unsigned int c = 0;
575 while (a) {
576 if (a & 1)
577 c ^= b;
578 a = a >> 1;
579 b = b << 1;
580 if (b & (1 << 16))
581 b ^= poly;
582 }
583 return c;
584 }
585
586 static unsigned int
pow_poly(unsigned int a,unsigned int n,unsigned int poly)587 pow_poly(unsigned int a,
588 unsigned int n,
589 unsigned int poly) {
590 unsigned int r = 1;
591 while (n) {
592 if (n & 1)
593 r = mul_poly(r, a, poly);
594 a = mul_poly(a, a, poly);
595 n >>= 1;
596 }
597 return r;
598 }
599
600 static uint16_t
calculate_crc1(unsigned char const * buf,std::size_t frame_size)601 calculate_crc1(unsigned char const *buf,
602 std::size_t frame_size) {
603 int frame_size_words = frame_size >> 1;
604 int frame_size_58 = (frame_size_words >> 1) + (frame_size_words >> 3);
605
606 uint16_t crc1 = mtx::bytes::swap_16(mtx::checksum::calculate_as_uint(mtx::checksum::algorithm_e::crc16_ansi, buf + 4, 2 * frame_size_58 - 4));
607 unsigned int crc_inv = pow_poly((CRC16_POLY >> 1), (16 * frame_size_58) - 16, CRC16_POLY);
608
609 return mul_poly(crc_inv, crc1, CRC16_POLY);
610 }
611
612 static uint16_t
calculate_crc2(unsigned char const * buf,std::size_t frame_size)613 calculate_crc2(unsigned char const *buf,
614 std::size_t frame_size) {
615 return mtx::bytes::swap_16(mtx::checksum::calculate_as_uint(mtx::checksum::algorithm_e::crc16_ansi, &buf[2], frame_size - 4));
616 }
617
618 bool
verify_checksums(unsigned char const * buf,std::size_t size,bool full_buffer)619 verify_checksums(unsigned char const *buf,
620 std::size_t size,
621 bool full_buffer) {
622 while (size) {
623 frame_c frame;
624
625 auto res = frame.decode_header(buf, size);
626
627 if (!res)
628 return false;
629
630 if (size < frame.m_bytes)
631 return false;
632
633 // crc1 is not present in E-AC-3.
634 if (!frame.is_eac3()) {
635 uint16_t expected_crc1 = get_uint16_be(&buf[2]);
636 auto actual_crc1 = calculate_crc1(buf, frame.m_bytes);
637
638 if (expected_crc1 != actual_crc1)
639 return false;
640 }
641
642 auto expected_crc2 = get_uint16_be(&buf[frame.m_bytes - 2]);
643 auto actual_crc2 = calculate_crc2(buf, frame.m_bytes);
644
645 if (expected_crc2 != actual_crc2)
646 return false;
647
648 if (!full_buffer)
649 break;
650
651 buf += frame.m_bytes;
652 size -= frame.m_bytes;
653 }
654
655 return true;
656 }
657
658 static void
remove_dialog_normalization_gain_impl(unsigned char * buf,frame_c & frame)659 remove_dialog_normalization_gain_impl(unsigned char *buf,
660 frame_c &frame) {
661 static debugging_option_c s_debug{"ac3_remove_dialog_normalization_gain|remove_dialog_normalization_gain"};
662
663
664 unsigned int const removed_level = 31;
665
666 if ( (frame.m_dialog_normalization_gain == removed_level)
667 && ( !frame.m_dialog_normalization_gain2
668 || (*frame.m_dialog_normalization_gain2 == removed_level))) {
669 mxdebug_if(s_debug, fmt::format("no need to remove the dialog normalization gain, it's already set to -{0} dB\n", removed_level));
670 return;
671 }
672
673 mxdebug_if(s_debug,
674 fmt::format("changing dialog normalization gain from -{0} dB ({1}) to -{2} dB\n",
675 frame.m_dialog_normalization_gain, frame.m_dialog_normalization_gain2 ? fmt::format("-{0} dB", *frame.m_dialog_normalization_gain2) : "—"s, removed_level));
676
677 mtx::bits::writer_c w{buf, frame.m_bytes};
678
679 w.set_bit_position(frame.m_dialog_normalization_gain_bit_position);
680 w.put_bits(5, removed_level);
681
682 if (frame.m_dialog_normalization_gain2_bit_position) {
683 w.set_bit_position(*frame.m_dialog_normalization_gain2_bit_position);
684 w.put_bits(5, removed_level);
685 }
686
687 // crc1 is not present in E-AC-3.
688 if (!frame.is_eac3())
689 put_uint16_be(&buf[2], calculate_crc1(buf, frame.m_bytes));
690
691 auto &crcrsv_byte = buf[frame.m_bytes - 3];
692 crcrsv_byte &= 0xfe;
693
694 auto crc2 = calculate_crc2(buf, frame.m_bytes);
695 if (crc2 == SYNC_WORD) {
696 crcrsv_byte |= 0x01;
697 crc2 = calculate_crc2(buf, frame.m_bytes);
698 }
699
700 put_uint16_be(&buf[frame.m_bytes - 2], crc2);
701 }
702
703 void
remove_dialog_normalization_gain(unsigned char * buf,std::size_t size)704 remove_dialog_normalization_gain(unsigned char *buf,
705 std::size_t size) {
706 while (true) {
707 frame_c frame;
708
709 if (!frame.decode_header(buf, size))
710 return;
711
712 if (size < frame.m_bytes)
713 return;
714
715 remove_dialog_normalization_gain_impl(buf, frame);
716
717 buf += frame.m_bytes;
718 size -= frame.m_bytes;
719 }
720 }
721
722 } // namespace mtx::ac3
723