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