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    Matroska reader
10 
11    Written by Moritz Bunkus <moritz@bunkus.org>.
12    Modified by Steve Lhomme <steve.lhomme@free.fr>.
13 */
14 
15 #include "common/common_pch.h"
16 
17 #include <cmath>
18 
19 #include <QDateTime>
20 #include <QRegularExpression>
21 
22 #include <ebml/EbmlContexts.h>
23 #include <ebml/EbmlHead.h>
24 #include <ebml/EbmlStream.h>
25 #include <ebml/EbmlSubHead.h>
26 #include <ebml/EbmlVoid.h>
27 #include <matroska/FileKax.h>
28 
29 #include <matroska/KaxAttached.h>
30 #include <matroska/KaxAttachments.h>
31 #include <matroska/KaxBlock.h>
32 #include <matroska/KaxBlockData.h>
33 #include <matroska/KaxChapters.h>
34 #include <matroska/KaxCluster.h>
35 #include <matroska/KaxClusterData.h>
36 #include <matroska/KaxContexts.h>
37 #include <matroska/KaxInfo.h>
38 #include <matroska/KaxInfoData.h>
39 #include <matroska/KaxSeekHead.h>
40 #include <matroska/KaxSegment.h>
41 #include <matroska/KaxTag.h>
42 #include <matroska/KaxTags.h>
43 #include <matroska/KaxTracks.h>
44 #include <matroska/KaxTrackAudio.h>
45 #include <matroska/KaxTrackVideo.h>
46 
47 #include "avilib.h"
48 #include "common/alac.h"
49 #include "common/at_scope_exit.h"
50 #include "common/chapters/chapters.h"
51 #include "common/codec.h"
52 #include "common/container.h"
53 #include "common/date_time.h"
54 #include "common/debugging.h"
55 #include "common/ebml.h"
56 #include "common/endian.h"
57 #include "common/hacks.h"
58 #include "common/iso639.h"
59 #include "common/ivf.h"
60 #include "common/kax_analyzer.h"
61 #include "common/math.h"
62 #include "common/mm_io.h"
63 #include "common/qt.h"
64 #include "common/strings/formatting.h"
65 #include "common/strings/parsing.h"
66 #include "common/strings/utf8.h"
67 #include "common/tags/tags.h"
68 #include "common/tags/vorbis.h"
69 #include "common/id_info.h"
70 #include "common/vobsub.h"
71 #include "input/r_matroska.h"
72 #include "merge/file_status.h"
73 #include "merge/input_x.h"
74 #include "merge/output_control.h"
75 #include "output/p_aac.h"
76 #include "output/p_ac3.h"
77 #include "output/p_alac.h"
78 #include "output/p_av1.h"
79 #include "output/p_avc.h"
80 #include "output/p_avc_es.h"
81 #include "output/p_dirac.h"
82 #include "output/p_dts.h"
83 #include "output/p_dvbsub.h"
84 #if defined(HAVE_FLAC_FORMAT_H)
85 # include "output/p_flac.h"
86 #endif
87 #include "output/p_hdmv_pgs.h"
88 #include "output/p_hdmv_textst.h"
89 #include "output/p_hevc.h"
90 #include "output/p_hevc_es.h"
91 #include "output/p_kate.h"
92 #include "output/p_mp3.h"
93 #include "output/p_mpeg1_2.h"
94 #include "output/p_mpeg4_p2.h"
95 #include "output/p_opus.h"
96 #include "output/p_passthrough.h"
97 #include "output/p_pcm.h"
98 #include "output/p_prores.h"
99 #include "output/p_ssa.h"
100 #include "output/p_textsubs.h"
101 #include "output/p_theora.h"
102 #include "output/p_truehd.h"
103 #include "output/p_tta.h"
104 #include "output/p_video_for_windows.h"
105 #include "output/p_vobbtn.h"
106 #include "output/p_vobsub.h"
107 #include "output/p_vorbis.h"
108 #include "output/p_vc1.h"
109 #include "output/p_vpx.h"
110 #include "output/p_wavpack.h"
111 #include "output/p_webvtt.h"
112 
113 using namespace libmatroska;
114 
115 namespace {
116 unsigned int
writing_app_ver(unsigned int major,unsigned int minor,unsigned int patchlevel,unsigned int errata)117 writing_app_ver(unsigned int major,
118                 unsigned int minor,
119                 unsigned int patchlevel,
120                 unsigned int errata) {
121   return (major << 24) | (minor << 16) | (patchlevel << 8) | errata;
122 }
123 
124 auto
map_track_type(char c)125 map_track_type(char c) {
126   return c == 'a' ? track_audio
127        : c == 'b' ? track_buttons
128        : c == 'v' ? track_video
129        :            track_subtitle;
130 }
131 
132 auto
map_track_type_string(char c)133 map_track_type_string(char c) {
134   return c == '?' ? Y("unknown")
135        : c == 'a' ? Y("audio")
136        : c == 'b' ? Y("buttons")
137        : c == 'v' ? Y("video")
138        :            Y("subtitle");
139 }
140 
141 constexpr auto MAGIC_MKV = 0x1a45dfa3;
142 
143 } // anonymous namespace
144 
145 void
handle_packetizer_display_dimensions()146 kax_track_t::handle_packetizer_display_dimensions() {
147   // If user hasn't set an aspect ratio via the command line and the
148   // source file provides display width/height paramaters then use
149   // these and signal the packetizer not to extract the dimensions
150   // from the bitstream.
151   if ((0 != v_dwidth) && (0 != v_dheight))
152     ptzr_ptr->set_video_display_dimensions(v_dwidth, v_dheight, v_dunit.value_or(generic_packetizer_c::ddu_pixels), OPTION_SOURCE_CONTAINER);
153 }
154 
155 void
handle_packetizer_pixel_cropping()156 kax_track_t::handle_packetizer_pixel_cropping() {
157   if ((0 < v_pcleft) || (0 < v_pctop) || (0 < v_pcright) || (0 < v_pcbottom))
158     ptzr_ptr->set_video_pixel_cropping(v_pcleft, v_pctop, v_pcright, v_pcbottom, OPTION_SOURCE_CONTAINER);
159 }
160 
161 void
handle_packetizer_colour()162 kax_track_t::handle_packetizer_colour() {
163   if (v_colour_matrix != -1)
164     ptzr_ptr->set_video_colour_matrix(v_colour_matrix, OPTION_SOURCE_CONTAINER);
165   if (v_bits_per_channel != -1)
166     ptzr_ptr->set_video_bits_per_channel(v_bits_per_channel, OPTION_SOURCE_CONTAINER);
167   if (v_chroma_subsample.hori != -1 || v_chroma_subsample.vert != -1)
168     ptzr_ptr->set_video_chroma_subsample(v_chroma_subsample, OPTION_SOURCE_CONTAINER);
169   if (v_cb_subsample.hori != -1 || v_cb_subsample.vert != -1)
170     ptzr_ptr->set_video_cb_subsample(v_cb_subsample, OPTION_SOURCE_CONTAINER);
171   if (v_chroma_siting.hori != -1 || v_chroma_siting.vert != -1)
172     ptzr_ptr->set_video_chroma_siting(v_chroma_siting, OPTION_SOURCE_CONTAINER);
173   if (v_colour_range != -1)
174     ptzr_ptr->set_video_colour_range(v_colour_range, OPTION_SOURCE_CONTAINER);
175   if (v_transfer_character != -1)
176     ptzr_ptr->set_video_colour_transfer_character(v_transfer_character, OPTION_SOURCE_CONTAINER);
177   if (v_colour_primaries != -1)
178     ptzr_ptr->set_video_colour_primaries(v_colour_primaries, OPTION_SOURCE_CONTAINER);
179   if (v_max_cll != -1)
180     ptzr_ptr->set_video_max_cll(v_max_cll, OPTION_SOURCE_CONTAINER);
181   if (v_max_fall != -1)
182     ptzr_ptr->set_video_max_fall(v_max_fall, OPTION_SOURCE_CONTAINER);
183   if (   (v_chroma_coordinates.red_x   != -1) || (v_chroma_coordinates.red_y   != -1)
184       || (v_chroma_coordinates.green_x != -1) || (v_chroma_coordinates.green_y != -1)
185       || (v_chroma_coordinates.blue_x  != -1) || (v_chroma_coordinates.blue_y  != -1)) {
186     ptzr_ptr->set_video_chroma_coordinates(v_chroma_coordinates, OPTION_SOURCE_CONTAINER);
187   }
188   if (v_white_colour_coordinates.x != -1 || v_white_colour_coordinates.y != -1)
189     ptzr_ptr->set_video_white_colour_coordinates(v_white_colour_coordinates, OPTION_SOURCE_CONTAINER);
190   if (v_max_luminance != -1)
191     ptzr_ptr->set_video_max_luminance(v_max_luminance, OPTION_SOURCE_CONTAINER);
192   if (v_min_luminance != -1)
193     ptzr_ptr->set_video_min_luminance(v_min_luminance, OPTION_SOURCE_CONTAINER);
194 
195   if (v_projection_type)
196     ptzr_ptr->set_video_projection_type(*v_projection_type, OPTION_SOURCE_CONTAINER);
197   if (v_projection_private)
198     ptzr_ptr->set_video_projection_private(v_projection_private, OPTION_SOURCE_CONTAINER);
199   if (v_projection_pose_yaw)
200     ptzr_ptr->set_video_projection_pose_yaw(*v_projection_pose_yaw, OPTION_SOURCE_CONTAINER);
201   if (v_projection_pose_pitch)
202     ptzr_ptr->set_video_projection_pose_pitch(*v_projection_pose_pitch, OPTION_SOURCE_CONTAINER);
203   if (v_projection_pose_roll)
204     ptzr_ptr->set_video_projection_pose_roll(*v_projection_pose_roll, OPTION_SOURCE_CONTAINER);
205 
206   if (codec_id == MKV_V_UNCOMPRESSED)
207     ptzr_ptr->set_video_colour_space(v_colour_space, OPTION_SOURCE_CONTAINER);
208 }
209 
210 void
handle_packetizer_field_order()211 kax_track_t::handle_packetizer_field_order() {
212   if (-1 != v_field_order)
213     ptzr_ptr->set_video_field_order(v_field_order, OPTION_SOURCE_CONTAINER);
214 }
215 
216 void
handle_packetizer_stereo_mode()217 kax_track_t::handle_packetizer_stereo_mode() {
218   if (stereo_mode_c::unspecified != v_stereo_mode)
219     ptzr_ptr->set_video_stereo_mode(v_stereo_mode, OPTION_SOURCE_CONTAINER);
220 }
221 
222 void
handle_packetizer_pixel_dimensions()223 kax_track_t::handle_packetizer_pixel_dimensions() {
224   if ((0 == v_width) || (0 == v_height))
225     return;
226 
227   ptzr_ptr->set_video_pixel_width(v_width);
228   ptzr_ptr->set_video_pixel_height(v_height);
229 }
230 
231 void
handle_packetizer_default_duration()232 kax_track_t::handle_packetizer_default_duration() {
233   if (0 != default_duration)
234     ptzr_ptr->set_track_default_duration(default_duration);
235 }
236 
237 void
handle_packetizer_output_sampling_freq()238 kax_track_t::handle_packetizer_output_sampling_freq() {
239   if (0 != a_osfreq)
240     ptzr_ptr->set_audio_output_sampling_freq(a_osfreq);
241 }
242 
243 void
handle_packetizer_codec_delay()244 kax_track_t::handle_packetizer_codec_delay() {
245   if (codec_delay.valid() && (codec_delay.to_ns() > 0))
246     ptzr_ptr->set_codec_delay(codec_delay);
247 }
248 
249 void
handle_packetizer_block_addition_mapping()250 kax_track_t::handle_packetizer_block_addition_mapping() {
251   ptzr_ptr->set_block_addition_mappings(block_addition_mappings);
252 }
253 
254 /* Fix display dimension parameters
255 
256    Certain Matroska muxers abuse the DisplayWidth/DisplayHeight
257    parameters for only storing an aspect ratio. These values are
258    usually very small, e.g. 16/9. Fix them so that the quotient is
259    kept but the values are in the range of the PixelWidth/PixelHeight
260    elements.
261  */
262 void
fix_display_dimension_parameters()263 kax_track_t::fix_display_dimension_parameters() {
264   if ((0 != v_display_unit) || ((8 * v_dwidth) > v_width) || ((8 * v_dheight) > v_height))
265     return;
266 
267   if (std::gcd(v_dwidth, v_dheight) != 1)
268     return;
269 
270   // max shrinking was applied, ie x264 style
271   if (v_dwidth > v_dheight) {
272     if (((v_height * v_dwidth) % v_dheight) == 0) { // only if we get get an exact count of pixels
273       v_dwidth  = v_height * v_dwidth / v_dheight;
274       v_dheight = v_height;
275     }
276   } else if (((v_width * v_dheight) % v_dwidth) == 0) {
277     v_dwidth  = v_width;
278     v_dheight = v_width * v_dheight / v_dwidth;
279   }
280 }
281 
282 void
get_source_id_from_track_statistics_tags()283 kax_track_t::get_source_id_from_track_statistics_tags() {
284   if (!tags)
285     return;
286 
287   for (auto const &tags_child : *tags) {
288     if (!dynamic_cast<KaxTag *>(tags_child))
289       continue;
290 
291     auto value = mtx::tags::get_simple_value("SOURCE_ID", static_cast<KaxTag &>(*tags_child));
292     if (value.empty())
293       continue;
294 
295     source_id = value;
296     return;
297   }
298 }
299 
300 void
discard_track_statistics_tags()301 kax_track_t::discard_track_statistics_tags() {
302   if (!tags)
303     return;
304 
305   mtx::tags::remove_track_statistics(tags.get(), track_uid);
306 
307   if (!tags->ListSize())
308     tags.reset();
309 }
310 
311 /*
312    Probes a file by simply comparing the first four bytes to the EBML
313    head signature.
314 */
315 bool
probe_file()316 kax_reader_c::probe_file() {
317   unsigned char data[4];
318   return (m_in->read(data, 4) == 4) && (get_uint32_be(data) == MAGIC_MKV);
319 }
320 
kax_reader_c()321 kax_reader_c::kax_reader_c() {
322   init_l1_position_storage(m_deferred_l1_positions);
323   init_l1_position_storage(m_handled_l1_positions);
324 }
325 
326 void
init_l1_position_storage(deferred_positions_t & storage)327 kax_reader_c::init_l1_position_storage(deferred_positions_t &storage) {
328   storage[dl1t_attachments] = std::vector<int64_t>();
329   storage[dl1t_chapters]    = std::vector<int64_t>();
330   storage[dl1t_tags]        = std::vector<int64_t>();
331   storage[dl1t_tracks]      = std::vector<int64_t>();
332   storage[dl1t_seek_head]   = std::vector<int64_t>();
333 }
334 
335 bool
packets_available()336 kax_reader_c::packets_available() {
337   for (auto &track : m_tracks)
338     if ((-1 != track->ptzr) && !ptzr(track->ptzr).packet_available())
339       return false;
340 
341   return !m_tracks.empty();
342 }
343 
344 kax_track_t *
find_track_by_num(uint64_t n,kax_track_t * c)345 kax_reader_c::find_track_by_num(uint64_t n,
346                                 kax_track_t *c) {
347   auto itr = std::find_if(m_tracks.begin(), m_tracks.end(), [n, c](auto &track) { return (track->track_number == n) && (track.get() != c); });
348   return itr == m_tracks.end() ? nullptr : itr->get();
349 }
350 
351 kax_track_t *
find_track_by_uid(uint64_t uid,kax_track_t * c)352 kax_reader_c::find_track_by_uid(uint64_t uid,
353                                 kax_track_t *c) {
354   auto itr = std::find_if(m_tracks.begin(), m_tracks.end(), [uid, c](auto &track) { return (track->track_uid == uid) && (track.get() != c); });
355   return itr == m_tracks.end() ? nullptr : itr->get();
356 }
357 
358 bool
unlace_vorbis_private_data(kax_track_t * t,unsigned char * buffer,int size)359 kax_reader_c::unlace_vorbis_private_data(kax_track_t *t,
360                                          unsigned char *buffer,
361                                          int size) {
362   try {
363     t->headers = unlace_memory_xiph(memory_c::borrow(buffer, size));
364     for (auto const &header : t->headers)
365       header->take_ownership();
366 
367   } catch (...) {
368     return false;
369   }
370 
371   return true;
372 }
373 
374 bool
verify_acm_audio_track(kax_track_t * t)375 kax_reader_c::verify_acm_audio_track(kax_track_t *t) {
376   if (!t->private_data || (sizeof(alWAVEFORMATEX) > t->private_data->get_size())) {
377     if (verbose)
378       mxwarn(fmt::format(Y("matroska_reader: The CodecID for track {0} is '{1}', but there was no WAVEFORMATEX struct present. "
379                            "Therefore we don't have a format ID to identify the audio codec used.\n"), t->tnum, MKV_A_ACM));
380     return false;
381 
382   }
383 
384   auto wfe       = reinterpret_cast<alWAVEFORMATEX *>(t->private_data->get_buffer());
385   t->a_formattag = get_uint16_le(&wfe->w_format_tag);
386   t->codec       = codec_c::look_up_audio_format(t->a_formattag);
387 
388   if (t->codec.is(codec_c::type_e::A_VORBIS) && (!unlace_vorbis_private_data(t, t->private_data->get_buffer() + sizeof(alWAVEFORMATEX), t->private_data->get_size() - sizeof(alWAVEFORMATEX)))) {
389     // Force the passthrough packetizer to be used if the data behind
390     // the WAVEFORMATEX does not contain valid laced Vorbis headers.
391     t->codec = codec_c{};
392     return true;
393   }
394 
395   t->ms_compat = 1;
396   uint32_t u   = get_uint32_le(&wfe->n_samples_per_sec);
397 
398   if (static_cast<uint32_t>(t->a_sfreq) != u) {
399     if (verbose)
400       mxwarn(fmt::format(Y("matroska_reader: (MS compatibility mode for track {0}) Matroska says that there are {1} samples per second, "
401                            "but WAVEFORMATEX says that there are {2}.\n"), t->tnum, static_cast<int>(t->a_sfreq), u));
402     if (0.0 == t->a_sfreq)
403       t->a_sfreq = static_cast<double>(u);
404   }
405 
406   u = get_uint16_le(&wfe->n_channels);
407   if (t->a_channels != u) {
408     if (verbose)
409       mxwarn(fmt::format(Y("matroska_reader: (MS compatibility mode for track {0}) Matroska says that there are {1} channels, "
410                            "but the WAVEFORMATEX says that there are {2}.\n"), t->tnum, t->a_channels, u));
411     if (0 == t->a_channels)
412       t->a_channels = u;
413   }
414 
415   u = get_uint16_le(&wfe->w_bits_per_sample);
416   if (t->a_bps != u) {
417     if (verbose && t->codec.is(codec_c::type_e::A_PCM))
418       mxwarn(fmt::format(Y("matroska_reader: (MS compatibility mode for track {0}) Matroska says that there are {1} bits per sample, "
419                            "but the WAVEFORMATEX says that there are {2}.\n"), t->tnum, t->a_bps, u));
420     if (0 == t->a_bps)
421       t->a_bps = u;
422   }
423 
424   return true;
425 }
426 
427 bool
verify_alac_audio_track(kax_track_t * t)428 kax_reader_c::verify_alac_audio_track(kax_track_t *t) {
429   if (t->private_data && (sizeof(mtx::alac::codec_config_t) <= t->private_data->get_size()))
430     return true;
431 
432   if (verbose)
433     mxwarn(fmt::format(Y("matroska_reader: The CodecID for track {0} is '{1}', but the private codec data does not contain valid headers.\n"), t->tnum, MKV_A_VORBIS));
434 
435   return false;
436 }
437 
438 bool
verify_dts_audio_track(kax_track_t * t)439 kax_reader_c::verify_dts_audio_track(kax_track_t *t) {
440   try {
441     read_first_frames(t, 5);
442 
443     mtx::bytes::buffer_c buffer;
444     for (auto &frame : t->first_frames_data)
445       buffer.add(*frame);
446 
447     if (-1 == mtx::dts::find_header(buffer.get_buffer(), buffer.get_size(), t->dts_header))
448       return false;
449 
450     t->a_channels = t->dts_header.get_total_num_audio_channels();
451     t->codec.set_specialization(t->dts_header.get_codec_specialization());
452 
453   } catch (...) {
454     return false;
455   }
456 
457   return true;
458 }
459 
460 #if defined(HAVE_FLAC_FORMAT_H)
461 bool
verify_flac_audio_track(kax_track_t *)462 kax_reader_c::verify_flac_audio_track(kax_track_t *) {
463   return true;
464 }
465 
466 #else
467 
468 bool
verify_flac_audio_track(kax_track_t * t)469 kax_reader_c::verify_flac_audio_track(kax_track_t *t) {
470   mxwarn(fmt::format(Y("matroska_reader: mkvmerge was not compiled with FLAC support. Ignoring track {0}.\n"), t->tnum));
471   return false;
472 }
473 #endif
474 
475 bool
verify_vorbis_audio_track(kax_track_t * t)476 kax_reader_c::verify_vorbis_audio_track(kax_track_t *t) {
477   if (!t->private_data || !unlace_vorbis_private_data(t, t->private_data->get_buffer(), t->private_data->get_size())) {
478     if (verbose)
479       mxwarn(fmt::format(Y("matroska_reader: The CodecID for track {0} is '{1}', but the private codec data does not contain valid headers.\n"), t->tnum, MKV_A_VORBIS));
480     return false;
481   }
482 
483   // mkvmerge around 0.6.x had a bug writing a default duration
484   // for Vorbis m_tracks but not the correct durations for the
485   // individual packets. This comes back to haunt us because
486   // when regenerating the timestamps from lacing those durations
487   // are used and add up to too large a value. The result is the
488   // usual "timestamp < m_last_timestamp" message.
489   // Workaround: do not use durations for such m_tracks.
490   if ((m_writing_app == "mkvmerge") && (-1 != m_writing_app_ver) && (writing_app_ver(7, 0, 0, 0) > m_writing_app_ver))
491     t->ignore_duration_hack = true;
492 
493   handle_vorbis_comments(*t);
494 
495   return true;
496 }
497 
498 bool
verify_opus_audio_track(kax_track_t * t)499 kax_reader_c::verify_opus_audio_track(kax_track_t *t) {
500   if (!t->private_data || !t->private_data->get_size()) {
501     if (verbose)
502       mxwarn(fmt::format(Y("matroska_reader: The CodecID for track {0} is '{1}', but the private codec data does not contain valid headers.\n"), t->tnum, MKV_A_OPUS));
503     return false;
504   }
505 
506   return true;
507 }
508 
509 bool
verify_truehd_audio_track(kax_track_t * t)510 kax_reader_c::verify_truehd_audio_track(kax_track_t *t) {
511   try {
512     int num_frames_to_probe = 5;
513 
514     while (num_frames_to_probe <= 2000) {
515       read_first_frames(t, num_frames_to_probe);
516 
517       mtx::truehd::parser_c parser;
518       for (auto &frame : t->first_frames_data)
519         parser.add_data(frame->get_buffer(), frame->get_size());
520 
521       while (parser.frame_available()) {
522         auto frame = parser.get_next_frame();
523 
524         if (frame->is_ac3() || !frame->is_sync())
525           continue;
526 
527         t->codec = frame->codec();
528 
529         return true;
530       }
531 
532       num_frames_to_probe *= 20;
533     }
534 
535   } catch (...) {
536   }
537 
538   return false;
539 }
540 
541 bool
verify_ac3_audio_track(kax_track_t * t)542 kax_reader_c::verify_ac3_audio_track(kax_track_t *t) {
543   try {
544     read_first_frames(t, 5);
545 
546     mtx::ac3::parser_c parser;
547     for (auto &frame : t->first_frames_data)
548       parser.add_bytes(frame->get_buffer(), frame->get_size());
549 
550     if (parser.frame_available()) {
551       t->codec = parser.get_frame().get_codec();
552       return true;
553     }
554 
555   } catch (...) {
556   }
557 
558   return false;
559 }
560 
561 void
verify_audio_track(kax_track_t * t)562 kax_reader_c::verify_audio_track(kax_track_t *t) {
563   if (t->codec_id.empty())
564     return;
565 
566   bool is_ok = true;
567   if (t->codec_id == MKV_A_ACM)
568     is_ok = verify_acm_audio_track(t);
569 
570   else {
571     t->codec = codec_c::look_up(t->codec_id);
572 
573     if (t->codec.is(codec_c::type_e::A_AC3))
574       is_ok = verify_ac3_audio_track(t);
575     else if (t->codec.is(codec_c::type_e::A_ALAC))
576       is_ok = verify_alac_audio_track(t);
577     else if (t->codec.is(codec_c::type_e::A_VORBIS))
578       is_ok = verify_vorbis_audio_track(t);
579     else if (t->codec.is(codec_c::type_e::A_FLAC))
580       is_ok = verify_flac_audio_track(t);
581     else if (t->codec.is(codec_c::type_e::A_OPUS))
582       is_ok = verify_opus_audio_track(t);
583     else if (t->codec.is(codec_c::type_e::A_DTS))
584       is_ok = verify_dts_audio_track(t);
585     else if (t->codec.is(codec_c::type_e::A_TRUEHD))
586       is_ok = verify_truehd_audio_track(t);
587   }
588 
589   if (!is_ok)
590     return;
591 
592   if (0.0 == t->a_sfreq)
593     t->a_sfreq = 8000.0;
594 
595   if (0 == t->a_channels)
596     t->a_channels = 1;
597 
598   // This track seems to be ok.
599   t->ok = 1;
600 }
601 
602 bool
verify_mscomp_video_track(kax_track_t * t)603 kax_reader_c::verify_mscomp_video_track(kax_track_t *t) {
604   if (!t->private_data || (sizeof(alBITMAPINFOHEADER) > t->private_data->get_size())) {
605     if (verbose)
606       mxwarn(fmt::format(Y("matroska_reader: The CodecID for track {0} is '{1}', but there was no BITMAPINFOHEADER struct present. "
607                            "Therefore we don't have a FourCC to identify the video codec used.\n"),
608                          t->tnum, MKV_V_MSCOMP));
609     return false;
610   }
611 
612   t->ms_compat = 1;
613   auto bih     = reinterpret_cast<alBITMAPINFOHEADER *>(t->private_data->get_buffer());
614   auto u       = get_uint32_le(&bih->bi_width);
615 
616   if (t->v_width != u) {
617     if (verbose)
618       mxwarn(fmt::format(Y("matroska_reader: (MS compatibility mode, track {0}) Matroska says video width is {1}, but the BITMAPINFOHEADER says {2}.\n"),
619                          t->tnum, t->v_width, u));
620     if (0 == t->v_width)
621       t->v_width = u;
622   }
623 
624   u = get_uint32_le(&bih->bi_height);
625   if (t->v_height != u) {
626     if (verbose)
627       mxwarn(fmt::format(Y("matroska_reader: (MS compatibility mode, track {0}) Matroska says video height is {1}, but the BITMAPINFOHEADER says {2}.\n"),
628                          t->tnum, t->v_height, u));
629     if (0 == t->v_height)
630       t->v_height = u;
631   }
632 
633   memcpy(t->v_fourcc, &bih->bi_compression, 4);
634   t->v_fourcc[4] = 0;
635   t->codec       = codec_c::look_up(t->v_fourcc);
636 
637   return true;
638 }
639 
640 bool
verify_theora_video_track(kax_track_t * t)641 kax_reader_c::verify_theora_video_track(kax_track_t *t) {
642   if (t->private_data)
643     return true;
644 
645   if (verbose)
646     mxwarn(fmt::format(Y("matroska_reader: The CodecID for track {0} is '{1}', but there was no codec private headers.\n"), t->tnum, MKV_V_THEORA));
647 
648   return false;
649 }
650 
651 void
verify_video_track(kax_track_t * t)652 kax_reader_c::verify_video_track(kax_track_t *t) {
653   if (t->codec_id.empty())
654     return;
655 
656   bool is_ok = true;
657   if (t->codec_id == MKV_V_MSCOMP)
658     is_ok = verify_mscomp_video_track(t);
659 
660   else {
661     t->codec = codec_c::look_up(t->codec_id);
662 
663     if (t->codec.is(codec_c::type_e::V_THEORA))
664       is_ok = verify_theora_video_track(t);
665   }
666 
667   if (!is_ok)
668     return;
669 
670   if (0 == t->v_width) {
671     if (verbose)
672       mxwarn(fmt::format(Y("matroska_reader: The width for track {0} was not set.\n"), t->tnum));
673     return;
674   }
675 
676   if (0 == t->v_height) {
677     if (verbose)
678       mxwarn(fmt::format(Y("matroska_reader: The height for track {0} was not set.\n"), t->tnum));
679     return;
680   }
681 
682   // This track seems to be ok.
683   t->ok = 1;
684 }
685 
686 bool
verify_dvb_subtitle_track(kax_track_t * t)687 kax_reader_c::verify_dvb_subtitle_track(kax_track_t *t) {
688   if (!t->private_data || (t->private_data->get_size() < 4)) {
689     mxwarn(fmt::format(Y("matroska_reader: The CodecID for track {0} is '{1}', but the private codec data does not contain valid headers.\n"), t->tnum, t->codec_id));
690     return false;
691   }
692 
693   return true;
694 }
695 
696 bool
verify_hdmv_textst_subtitle_track(kax_track_t * t)697 kax_reader_c::verify_hdmv_textst_subtitle_track(kax_track_t *t) {
698   if (!t->private_data || (t->private_data->get_size() < 4)) {
699     mxwarn(fmt::format(Y("matroska_reader: The CodecID for track {0} is '{1}', but the private codec data does not contain valid headers.\n"), t->tnum, t->codec_id));
700     return false;
701   }
702 
703   // Older files created by MakeMKV have a different layout:
704   // 1 byte language code
705   // segment descriptor:
706   //   1 byte segment type (dialog style segment)
707   //   2 bytes segment size
708   // x bytes dialog style segment data
709   // 2 bytes frame count
710 
711   // Newer files will only contain the dialog style segment's
712   // descriptor and data
713 
714   auto buf                 = t->private_data->get_buffer();
715   auto old_style           = buf[0] && (buf[0] < 0x10);
716   auto style_segment_start = old_style ? 1 : 0;
717   auto style_segment_size  = get_uint16_be(&buf[style_segment_start + 1]);
718 
719   if (t->private_data->get_size() < static_cast<unsigned int>(3 + style_segment_size + (old_style ? 1 + 2 : 0))) {
720     mxwarn(fmt::format(Y("matroska_reader: The CodecID for track {0} is '{1}', but the private codec data does not contain valid headers.\n"), t->codec_id));
721     return false;
722   }
723 
724   if (0 < style_segment_start)
725     std::memmove(&buf[0], &buf[style_segment_start], style_segment_size);
726 
727   t->private_data->resize(style_segment_size + 3);
728 
729   return true;
730 }
731 
732 bool
verify_kate_subtitle_track(kax_track_t * t)733 kax_reader_c::verify_kate_subtitle_track(kax_track_t *t) {
734   if (t->private_data)
735     return true;
736 
737   if (verbose)
738     mxwarn(fmt::format(Y("matroska_reader: The CodecID for track {0} is '{1}', but there was no private data found.\n"), t->tnum, t->codec_id));
739 
740   return false;
741 }
742 
743 bool
verify_vobsub_subtitle_track(kax_track_t * t)744 kax_reader_c::verify_vobsub_subtitle_track(kax_track_t *t) {
745   if (t->private_data)
746     return true;
747 
748   if (!g_identifying && verbose)
749     mxwarn_fn(m_ti.m_fname,
750               fmt::format("{0} {1}\n",
751                           fmt::format(Y("The VobSub subtitle track {0} does not contain its index in the CodecPrivate element."), t->tnum),
752                           Y("A default index and with it default settings for the width, height and color palette will be used instead.")));
753 
754   t->private_data = memory_c::clone(mtx::vobsub::create_default_index(720, 576, {}));
755 
756   return true;
757 }
758 
759 void
verify_subtitle_track(kax_track_t * t)760 kax_reader_c::verify_subtitle_track(kax_track_t *t) {
761   auto is_ok = true;
762   t->codec   = codec_c::look_up(t->codec_id);
763 
764   if (t->codec.is(codec_c::type_e::S_VOBSUB))
765     is_ok = verify_vobsub_subtitle_track(t);
766 
767   else if (t->codec.is(codec_c::type_e::S_DVBSUB))
768     is_ok = verify_dvb_subtitle_track(t);
769 
770   else if (t->codec.is(codec_c::type_e::S_KATE))
771     is_ok = verify_kate_subtitle_track(t);
772 
773   else if (t->codec.is(codec_c::type_e::S_HDMV_TEXTST))
774     is_ok = verify_hdmv_textst_subtitle_track(t);
775 
776   t->ok = is_ok ? 1 : 0;
777 }
778 
779 void
verify_button_track(kax_track_t * t)780 kax_reader_c::verify_button_track(kax_track_t *t) {
781   t->codec = codec_c::look_up(t->codec_id);
782 
783   if (!t->codec.is(codec_c::type_e::B_VOBBTN)) {
784     if (verbose)
785       mxwarn(fmt::format(Y("matroska_reader: The CodecID '{0}' for track {1} is unknown.\n"), t->codec_id, t->tnum));
786     return;
787   }
788 
789   t->ok = 1;
790 }
791 
792 void
verify_tracks()793 kax_reader_c::verify_tracks() {
794   size_t tnum;
795   kax_track_t *t;
796 
797   for (tnum = 0; tnum < m_tracks.size(); tnum++) {
798     t = m_tracks[tnum].get();
799 
800     t->ok = t->content_decoder.is_ok();
801 
802     if (!t->ok)
803       continue;
804     t->ok = 0;
805 
806     if (t->private_data) {
807       t->content_decoder.reverse(t->private_data, CONTENT_ENCODING_SCOPE_CODECPRIVATE);
808     }
809 
810     switch (t->type) {
811       case 'v': verify_video_track(t);    break;
812       case 'a': verify_audio_track(t);    break;
813       case 's': verify_subtitle_track(t); break;
814       case 'b': verify_button_track(t);   break;
815 
816       default:                  // unknown track type!? error in demuxer...
817         if (verbose)
818           mxwarn(fmt::format(Y("matroska_reader: unknown demultiplexer type for track {0}: '{1}'\n"), t->tnum, t->type));
819         continue;
820     }
821 
822     if (t->ok && (1 < verbose))
823       mxinfo(fmt::format(Y("matroska_reader: Track {0} seems to be ok.\n"), t->tnum));
824   }
825 }
826 
827 bool
has_deferred_element_been_processed(kax_reader_c::deferred_l1_type_e type,int64_t position)828 kax_reader_c::has_deferred_element_been_processed(kax_reader_c::deferred_l1_type_e type,
829                                                   int64_t position) {
830   for (auto test_position : m_handled_l1_positions[type])
831     if (position == test_position)
832       return true;
833 
834   m_handled_l1_positions[type].push_back(position);
835 
836   return false;
837 }
838 
839 void
handle_attachments(mm_io_c * io,EbmlElement * l0,int64_t pos)840 kax_reader_c::handle_attachments(mm_io_c *io,
841                                  EbmlElement *l0,
842                                  int64_t pos) {
843   if (has_deferred_element_been_processed(dl1t_attachments, pos))
844     return;
845 
846   io->save_pos(pos);
847   mtx::at_scope_exit_c restore([io]() { io->restore_pos(); });
848 
849   int upper_lvl_el = 0;
850   std::shared_ptr<EbmlElement> l1(m_es->FindNextElement(EBML_CONTEXT(l0), upper_lvl_el, 0xFFFFFFFFL, true));
851   KaxAttachments *atts = dynamic_cast<KaxAttachments *>(l1.get());
852 
853   if (!atts)
854     return;
855 
856   EbmlElement *element_found = nullptr;
857   upper_lvl_el               = 0;
858 
859   atts->Read(*m_es, EBML_CLASS_CONTEXT(KaxAttachments), upper_lvl_el, element_found, true);
860   if (!found_in(*atts, element_found))
861     delete element_found;
862 
863   for (auto l1_att : *atts) {
864     auto att = dynamic_cast<KaxAttached *>(l1_att);
865     if (!att)
866       continue;
867 
868     ++m_attachment_id;
869 
870     auto fdata = FindChild<KaxFileData>(att);
871     if (!fdata)
872       continue;
873 
874     auto matt         = std::make_shared<attachment_t>();
875     matt->name        = to_utf8(FindChildValue<KaxFileName>(att));
876     matt->description = to_utf8(FindChildValue<KaxFileDescription>(att));
877     matt->mime_type   = FindChildValue<KaxMimeType>(att);
878     matt->id          = FindChildValue<KaxFileUID>(att);
879     matt->data        = memory_c::clone(static_cast<unsigned char *>(fdata->GetBuffer()), fdata->GetSize());
880 
881     auto attach_mode  = attachment_requested(m_attachment_id);
882 
883     if (   !matt->data->get_size()
884         || matt->mime_type.empty()
885         || (ATTACH_MODE_SKIP == attach_mode))
886       continue;
887 
888     matt->ui_id          = m_attachment_id;
889     matt->to_all_files   = ATTACH_MODE_TO_ALL_FILES == attach_mode;
890     matt->source_file    = m_ti.m_fname;
891 
892     add_attachment(matt);
893   }
894 }
895 
896 void
handle_chapters(mm_io_c * io,EbmlElement * l0,int64_t pos)897 kax_reader_c::handle_chapters(mm_io_c *io,
898                               EbmlElement *l0,
899                               int64_t pos) {
900   if (has_deferred_element_been_processed(dl1t_chapters, pos))
901     return;
902 
903   io->save_pos(pos);
904   mtx::at_scope_exit_c restore([io]() { io->restore_pos(); });
905 
906   int upper_lvl_el = 0;
907   std::shared_ptr<EbmlElement> l1(m_es->FindNextElement(EBML_CONTEXT(l0), upper_lvl_el, 0xFFFFFFFFL, true));
908   KaxChapters *tmp_chapters = dynamic_cast<KaxChapters *>(l1.get());
909 
910   if (!tmp_chapters)
911     return;
912 
913   EbmlElement *element_found = nullptr;
914   upper_lvl_el               = 0;
915 
916   tmp_chapters->Read(*m_es, EBML_CLASS_CONTEXT(KaxChapters), upper_lvl_el, element_found, true);
917   if (!found_in(*tmp_chapters, element_found))
918     delete element_found;
919 
920   if (m_regenerate_chapter_uids)
921     mtx::chapters::regenerate_uids(*tmp_chapters, m_tags.get());
922 
923   if (!m_chapters)
924     m_chapters = mtx::chapters::kax_cptr{new KaxChapters};
925 
926   m_chapters->GetElementList().insert(m_chapters->begin(), tmp_chapters->begin(), tmp_chapters->end());
927   tmp_chapters->RemoveAll();
928 }
929 
930 void
handle_tags(mm_io_c * io,EbmlElement * l0,int64_t pos)931 kax_reader_c::handle_tags(mm_io_c *io,
932                           EbmlElement *l0,
933                           int64_t pos) {
934   if (has_deferred_element_been_processed(dl1t_tags, pos))
935     return;
936 
937   io->save_pos(pos);
938   mtx::at_scope_exit_c restore([io]() { io->restore_pos(); });
939 
940   int upper_lvl_el = 0;
941   std::shared_ptr<EbmlElement> l1(m_es->FindNextElement(EBML_CONTEXT(l0), upper_lvl_el, 0xFFFFFFFFL, true));
942   KaxTags *tags = dynamic_cast<KaxTags *>(l1.get());
943 
944   if (!tags)
945     return;
946 
947   EbmlElement *element_found = nullptr;
948   upper_lvl_el               = 0;
949 
950   tags->Read(*m_es, EBML_CLASS_CONTEXT(KaxTags), upper_lvl_el, element_found, true);
951   if (!found_in(*tags, element_found))
952     delete element_found;
953 
954   while (tags->ListSize() > 0) {
955     if (!Is<KaxTag>((*tags)[0])) {
956       delete (*tags)[0];
957       tags->Remove(0);
958       continue;
959     }
960 
961     bool delete_tag       = true;
962     bool is_global        = true;
963     KaxTag *tag           = static_cast<KaxTag *>((*tags)[0]);
964     KaxTagTargets *target = FindChild<KaxTagTargets>(tag);
965 
966     if (target) {
967       KaxTagTrackUID *tuid = FindChild<KaxTagTrackUID>(target);
968 
969       if (tuid) {
970         is_global          = false;
971         kax_track_t *track = find_track_by_uid(tuid->GetValue());
972 
973         if (track) {
974           bool contains_tag = false;
975 
976           size_t i;
977           for (i = 0; i < tag->ListSize(); i++)
978             if (dynamic_cast<KaxTagSimple *>((*tag)[i])) {
979               contains_tag = true;
980               break;
981             }
982 
983           if (contains_tag) {
984             if (!track->tags)
985               track->tags.reset(new KaxTags);
986             track->tags->PushElement(*tag);
987 
988             delete_tag = false;
989           }
990         }
991       }
992     }
993 
994     if (is_global) {
995       if (!m_tags)
996         m_tags = std::shared_ptr<KaxTags>(new KaxTags);
997       m_tags->PushElement(*tag);
998 
999     } else if (delete_tag)
1000       delete tag;
1001 
1002     tags->Remove(0);
1003   }
1004 }
1005 
1006 void
handle_track_statistics_tags()1007 kax_reader_c::handle_track_statistics_tags() {
1008   for (auto const &track : m_tracks) {
1009     if (!m_ti.m_track_tags.none())
1010       track->get_source_id_from_track_statistics_tags();
1011 
1012     if (!mtx::hacks::is_engaged(mtx::hacks::KEEP_TRACK_STATISTICS_TAGS))
1013       track->discard_track_statistics_tags();
1014   }
1015 }
1016 
1017 void
read_headers_info(mm_io_c * io,EbmlElement * l0,int64_t pos)1018 kax_reader_c::read_headers_info(mm_io_c *io,
1019                                 EbmlElement *l0,
1020                                 int64_t pos) {
1021   // General info about this Matroska file
1022   if (has_deferred_element_been_processed(dl1t_info, pos))
1023     return;
1024 
1025   io->save_pos(pos);
1026   mtx::at_scope_exit_c restore([io]() { io->restore_pos(); });
1027 
1028   int upper_lvl_el = 0;
1029   std::shared_ptr<EbmlElement> l1(m_es->FindNextElement(EBML_CONTEXT(l0), upper_lvl_el, 0xFFFFFFFFL, true));
1030   KaxInfo *info = dynamic_cast<KaxInfo *>(l1.get());
1031 
1032   if (!info)
1033     return;
1034 
1035   EbmlElement *element_found = nullptr;
1036   upper_lvl_el               = 0;
1037 
1038   info->Read(*m_es, EBML_CLASS_CONTEXT(KaxInfo), upper_lvl_el, element_found, true);
1039   if (!found_in(*info, element_found))
1040     delete element_found;
1041 
1042   m_tc_scale          = FindChildValue<KaxTimecodeScale, uint64_t>(info, 1000000);
1043   m_segment_duration  = std::llround(FindChildValue<KaxDuration>(info) * m_tc_scale);
1044   m_title             = to_utf8(FindChildValue<KaxTitle>(info));
1045   auto muxing_date    = FindChild<KaxDateUTC>(info);
1046   if (muxing_date)
1047     m_muxing_date_epoch = muxing_date->GetEpochDate();
1048 
1049   m_in_file->set_timestamp_scale(m_tc_scale);
1050 
1051   // Let's try to parse the "writing application" string. This usually
1052   // contains the name and version number of the application used for
1053   // creating this Matroska file. Examples are:
1054   //
1055   // mkvmerge v0.6.6
1056   // mkvmerge v0.9.6 ('Every Little Kiss') built on Oct  7 2004 18:37:49
1057   // VirtualDubMod 1.5.4.1 (build 2178/release)
1058   // AVI-Mux GUI 1.16.8 MPEG test build 1, Aug 24 2004  12:42:57
1059   // HandBrake 0.10.2 2015060900
1060   //
1061   // The idea is to first replace known application names that contain
1062   // spaces with one that doesn't. Then split the whole std::string up on
1063   // spaces into at most three parts. If the result is at least two parts
1064   // long then try to parse the version number from the second and
1065   // store a lower case version of the first as the application's name.
1066   auto km_writing_app = FindChild<KaxWritingApp>(info);
1067   if (km_writing_app) {
1068     read_headers_info_writing_app(km_writing_app);
1069 
1070     // Workaround: HandBrake and other tools always assign sequential
1071     // numbers starting at 1 to UID attributes. This is a problem when
1072     // appending two files created by such a tool that contain chapters
1073     // as both files contain chapters with the same UIDs and mkvmerge
1074     // thinks those should be merged. So ignore the chapter UIDs for
1075     // files that aren't created by known-good applications.
1076     if (!Q(m_writing_app).contains(QRegularExpression{"^(?:mkvmerge|no_variable_data)", QRegularExpression::CaseInsensitiveOption}))
1077       m_regenerate_chapter_uids = true;
1078   }
1079 
1080   auto km_muxing_app = FindChild<KaxMuxingApp>(info);
1081   if (km_muxing_app) {
1082     m_muxing_app = km_muxing_app->GetValueUTF8();
1083 
1084     // DirectShow Muxer workaround: Gabest's DirectShow muxer
1085     // writes wrong references (off by 1ms). So let the cluster
1086     // helper be a bit more imprecise in what it accepts when
1087     // looking for referenced packets.
1088     if (m_muxing_app == "DirectShow Matroska Muxer")
1089       m_reference_timestamp_tolerance = 1000000;
1090   }
1091 
1092   m_segment_uid          = FindChildValue<KaxSegmentUID>(info);
1093   m_next_segment_uid     = FindChildValue<KaxNextUID>(info);
1094   m_previous_segment_uid = FindChildValue<KaxPrevUID>(info);
1095 }
1096 
1097 void
read_headers_info_writing_app(KaxWritingApp * & km_writing_app)1098 kax_reader_c::read_headers_info_writing_app(KaxWritingApp *&km_writing_app) {
1099   size_t idx;
1100 
1101   std::string s = km_writing_app->GetValueUTF8();
1102   mtx::string::strip(s);
1103 
1104   m_raw_writing_app = s;
1105 
1106   if (balg::istarts_with(s, "avi-mux gui"))
1107     s.replace(0, strlen("avi-mux gui"), "avimuxgui");
1108 
1109   auto parts = mtx::string::split(s.c_str(), " ", 3);
1110   if (parts.size() < 2) {
1111     m_writing_app = "";
1112     for (idx = 0; idx < s.size(); idx++)
1113       m_writing_app += tolower(s[idx]);
1114     m_writing_app_ver = -1;
1115 
1116   } else {
1117 
1118     m_writing_app = "";
1119     for (idx = 0; idx < parts[0].size(); idx++)
1120       m_writing_app += tolower(parts[0][idx]);
1121     s = "";
1122 
1123     for (idx = 0; idx < parts[1].size(); idx++)
1124       if (isdigit(parts[1][idx]) || (parts[1][idx] == '.'))
1125         s += parts[1][idx];
1126 
1127     auto ver_parts = mtx::string::split(s.c_str(), ".");
1128     for (idx = ver_parts.size(); idx < 4; idx++)
1129       ver_parts.push_back("0");
1130 
1131     bool failed     = false;
1132     m_writing_app_ver = 0;
1133 
1134     for (idx = 0; idx < 4; idx++) {
1135       int num;
1136 
1137       if (!mtx::string::parse_number(ver_parts[idx], num) || (0 > num) || (255 < num)) {
1138         failed = true;
1139         break;
1140       }
1141       m_writing_app_ver <<= 8;
1142       m_writing_app_ver  |= num;
1143     }
1144     if (failed)
1145       m_writing_app_ver = -1;
1146   }
1147 }
1148 
1149 void
read_headers_track_audio(kax_track_t * track,KaxTrackAudio * ktaudio)1150 kax_reader_c::read_headers_track_audio(kax_track_t *track,
1151                                        KaxTrackAudio *ktaudio) {
1152   track->a_sfreq    = FindChildValue<KaxAudioSamplingFreq>(ktaudio, 8000.0);
1153   track->a_osfreq   = FindChildValue<KaxAudioOutputSamplingFreq>(ktaudio);
1154   track->a_channels = FindChildValue<KaxAudioChannels>(ktaudio, 1);
1155   track->a_bps      = FindChildValue<KaxAudioBitDepth>(ktaudio);
1156 }
1157 
1158 void
read_headers_track_video(kax_track_t * track,KaxTrackVideo * ktvideo)1159 kax_reader_c::read_headers_track_video(kax_track_t *track,
1160                                        KaxTrackVideo *ktvideo) {
1161   track->v_width        = FindChildValue<KaxVideoPixelWidth>(ktvideo);
1162   track->v_height       = FindChildValue<KaxVideoPixelHeight>(ktvideo);
1163   track->v_dwidth       = FindChildValue<KaxVideoDisplayWidth>(ktvideo,  track->v_width);
1164   track->v_dheight      = FindChildValue<KaxVideoDisplayHeight>(ktvideo, track->v_height);
1165   track->v_dunit        = FindChildValue<KaxVideoDisplayUnit>(ktvideo,   generic_packetizer_c::ddu_pixels);
1166 
1167   track->v_pcleft       = FindChildValue<KaxVideoPixelCropLeft>(ktvideo);
1168   track->v_pcright      = FindChildValue<KaxVideoPixelCropRight>(ktvideo);
1169   track->v_pctop        = FindChildValue<KaxVideoPixelCropTop>(ktvideo);
1170   track->v_pcbottom     = FindChildValue<KaxVideoPixelCropBottom>(ktvideo);
1171 
1172   auto colour_space = FindChild<KaxVideoColourSpace>(*ktvideo);
1173   if (colour_space)
1174     track->v_colour_space = memory_c::clone(colour_space->GetBuffer(), colour_space->GetSize());
1175 
1176   auto colour           = FindChild<KaxVideoColour>(*ktvideo);
1177 
1178   if (colour) {
1179     track->v_colour_matrix         = FindChildValue<KaxVideoColourMatrix>(colour, -1);
1180     track->v_bits_per_channel      = FindChildValue<KaxVideoBitsPerChannel>(colour, -1);
1181     track->v_chroma_subsample.hori = FindChildValue<KaxVideoChromaSubsampHorz>(colour, -1);
1182     track->v_chroma_subsample.vert = FindChildValue<KaxVideoChromaSubsampVert>(colour, -1);
1183     track->v_cb_subsample.hori     = FindChildValue<KaxVideoCbSubsampHorz>(colour, -1);
1184     track->v_cb_subsample.vert     = FindChildValue<KaxVideoCbSubsampVert>(colour, -1);
1185     track->v_chroma_siting.hori    = FindChildValue<KaxVideoChromaSitHorz>(colour, -1);
1186     track->v_chroma_siting.vert    = FindChildValue<KaxVideoChromaSitVert>(colour, -1);
1187     track->v_colour_range          = FindChildValue<KaxVideoColourRange>(colour, -1);
1188     track->v_transfer_character    = FindChildValue<KaxVideoColourTransferCharacter>(colour, -1);
1189     track->v_colour_primaries      = FindChildValue<KaxVideoColourPrimaries>(colour, -1);
1190     track->v_max_cll               = FindChildValue<KaxVideoColourMaxCLL>(colour, -1);
1191     track->v_max_fall              = FindChildValue<KaxVideoColourMaxFALL>(colour, -1);
1192 
1193     auto colour_meta               = FindChild<KaxVideoColourMasterMeta>(*colour);
1194 
1195     if (colour_meta) {
1196       track->v_chroma_coordinates.red_x   = FindChildValue<KaxVideoRChromaX>(colour_meta, -1.0);
1197       track->v_chroma_coordinates.red_y   = FindChildValue<KaxVideoRChromaY>(colour_meta, -1.0);
1198       track->v_chroma_coordinates.green_x = FindChildValue<KaxVideoGChromaX>(colour_meta, -1.0);
1199       track->v_chroma_coordinates.green_y = FindChildValue<KaxVideoGChromaY>(colour_meta, -1.0);
1200       track->v_chroma_coordinates.blue_x  = FindChildValue<KaxVideoBChromaX>(colour_meta, -1.0);
1201       track->v_chroma_coordinates.blue_y  = FindChildValue<KaxVideoBChromaY>(colour_meta, -1.0);
1202       track->v_white_colour_coordinates.x = FindChildValue<KaxVideoWhitePointChromaX>(colour_meta, -1.0);
1203       track->v_white_colour_coordinates.y = FindChildValue<KaxVideoWhitePointChromaY>(colour_meta, -1.0);
1204       track->v_max_luminance              = FindChildValue<KaxVideoLuminanceMax>(colour_meta, -1.0);
1205       track->v_min_luminance              = FindChildValue<KaxVideoLuminanceMin>(colour_meta, -1.0);
1206     }
1207   }
1208 
1209   auto projection = FindChild<KaxVideoProjection>(*ktvideo);
1210 
1211   if (projection) {
1212     track->v_projection_type       = FindOptionalChildValue<KaxVideoProjectionType>(projection);
1213     track->v_projection_pose_yaw   = FindOptionalChildValue<KaxVideoProjectionPoseYaw>(projection);
1214     track->v_projection_pose_pitch = FindOptionalChildValue<KaxVideoProjectionPosePitch>(projection);
1215     track->v_projection_pose_roll  = FindOptionalChildValue<KaxVideoProjectionPoseRoll>(projection);
1216 
1217     auto kprojection_private = FindChild<KaxVideoProjectionPrivate>(projection);
1218     if (kprojection_private)
1219       track->v_projection_private = memory_c::clone(kprojection_private->GetBuffer(), kprojection_private->GetSize());
1220   }
1221 
1222   track->v_field_order  = FindChildValue<KaxVideoFieldOrder>(ktvideo, -1);
1223   track->v_stereo_mode  = FindChildValue<KaxVideoStereoMode, stereo_mode_c::mode>(ktvideo, stereo_mode_c::unspecified);
1224 
1225   // For older files.
1226   auto frame_rate       = FindChildValue<KaxVideoFrameRate>(ktvideo);
1227   track->v_display_unit = FindChildValue<KaxVideoDisplayUnit>(ktvideo);
1228 
1229   if (0 < frame_rate)
1230     track->default_duration = static_cast<int64_t>(1'000'000'000 / frame_rate);
1231 
1232   if (!track->v_width)
1233     mxerror(Y("matroska_reader: Pixel width is missing.\n"));
1234   if (!track->v_height)
1235     mxerror(Y("matroska_reader: Pixel height is missing.\n"));
1236 
1237   track->fix_display_dimension_parameters();
1238 }
1239 
1240 void
read_headers_tracks(mm_io_c * io,EbmlElement * l0,int64_t position)1241 kax_reader_c::read_headers_tracks(mm_io_c *io,
1242                                   EbmlElement *l0,
1243                                   int64_t position) {
1244   // Yep, we've found our KaxTracks element. Now find all m_tracks
1245   // contained in this segment.
1246   if (has_deferred_element_been_processed(dl1t_tracks, position))
1247     return;
1248 
1249   int upper_lvl_el = 0;
1250   io->save_pos(position);
1251   auto l1 = std::shared_ptr<EbmlElement>(m_es->FindNextElement(EBML_CONTEXT(l0), upper_lvl_el, 0xFFFFFFFFL, true));
1252 
1253   if (!l1 || !Is<KaxTracks>(*l1)) {
1254     io->restore_pos();
1255 
1256     return;
1257   }
1258 
1259   EbmlElement *element_found = nullptr;
1260   upper_lvl_el               = 0;
1261   l1->Read(*m_es, EBML_CLASS_CONTEXT(KaxTracks), upper_lvl_el, element_found, true);
1262   if (!found_in(*l1, element_found))
1263     delete element_found;
1264 
1265   for (auto *ktentry = FindChild<KaxTrackEntry>(*l1); ktentry; ktentry = FindNextChild(static_cast<EbmlMaster &>(*l1), *ktentry)) {
1266     // We actually found a track entry :) We're happy now.
1267     auto track  = std::make_shared<kax_track_t>();
1268     track->tnum = m_tracks.size();
1269 
1270     auto ktnum = FindChild<KaxTrackNumber>(ktentry);
1271     if (!ktnum) {
1272       mxdebug_if(m_debug_track_headers, fmt::format("matroska_reader: track ID {} is missing its track number.\n", track->tnum));
1273       continue;
1274     }
1275 
1276     track->track_number = ktnum->GetValue();
1277     if (find_track_by_num(track->track_number, track.get())) {
1278       mxdebug_if(m_debug_track_headers, fmt::format("matroska_reader: track number {} is already in use.\n", track->track_number));
1279       m_known_bad_track_numbers[track->track_number] = true;
1280       continue;
1281     }
1282 
1283     auto ktuid = FindChild<KaxTrackUID>(ktentry);
1284     if (!ktuid)
1285       mxwarn_fn(m_ti.m_fname,
1286                 fmt::format(Y("Track {0} is missing its track UID element which is required to be present by the Matroska specification. If the file contains tags then those tags might be broken.\n"),
1287                             track->tnum));
1288     else
1289       track->track_uid = ktuid->GetValue();
1290 
1291     auto kttype = FindChild<KaxTrackType>(ktentry);
1292     if (!kttype) {
1293       mxdebug_if(m_debug_track_headers, fmt::format("matroska_reader: track number {} is missing the track type.\n", track->track_number));
1294       m_known_bad_track_numbers[track->track_number] = true;
1295       continue;
1296     }
1297 
1298     unsigned char track_type = kttype->GetValue();
1299     track->type              = track_type == track_audio    ? 'a'
1300                              : track_type == track_video    ? 'v'
1301                              : track_type == track_subtitle ? 's'
1302                              :                                '?';
1303 
1304     auto ktaudio = FindChild<KaxTrackAudio>(ktentry);
1305     if (ktaudio)
1306       read_headers_track_audio(track.get(), ktaudio);
1307 
1308     auto ktvideo = FindChild<KaxTrackVideo>(ktentry);
1309     if (ktvideo)
1310       read_headers_track_video(track.get(), ktvideo);
1311 
1312     auto kcodecpriv = FindChild<KaxCodecPrivate>(ktentry);
1313     if (kcodecpriv)
1314       track->private_data = memory_c::clone(kcodecpriv->GetBuffer(), kcodecpriv->GetSize());
1315 
1316     track->codec_id               = FindChildValue<KaxCodecID>(ktentry);
1317     track->codec_name             = to_utf8(FindChildValue<KaxCodecName>(ktentry));
1318     track->track_name             = to_utf8(FindChildValue<KaxTrackName>(ktentry));
1319     track->language               = mtx::bcp47::language_c::parse(FindChildValue<KaxTrackLanguage, std::string>(ktentry, "eng"));
1320     track->language_ietf          = mtx::bcp47::language_c::parse(FindChildValue<KaxLanguageIETF, std::string>(ktentry, {}));
1321     track->default_duration       = FindChildValue<KaxTrackDefaultDuration>(ktentry, track->default_duration);
1322     track->default_track          = FindChildValue<KaxTrackFlagDefault, bool>(ktentry, true);
1323     track->forced_track           = FindChildValue<KaxTrackFlagForced>(ktentry);
1324     track->enabled_track          = FindChildValue<KaxTrackFlagEnabled, bool>(ktentry, true);
1325     track->lacing_flag            = FindChildValue<KaxTrackFlagLacing>(ktentry);
1326     track->max_blockadd_id        = FindChildValue<KaxMaxBlockAdditionID>(ktentry);
1327     track->hearing_impaired_flag  = FindOptionalChildBoolValue<KaxFlagHearingImpaired>(ktentry);
1328     track->visual_impaired_flag   = FindOptionalChildBoolValue<KaxFlagVisualImpaired>(ktentry);
1329     track->text_descriptions_flag = FindOptionalChildBoolValue<KaxFlagTextDescriptions>(ktentry);
1330     track->original_flag          = FindOptionalChildBoolValue<KaxFlagOriginal>(ktentry);
1331     track->commentary_flag        = FindOptionalChildBoolValue<KaxFlagCommentary>(ktentry);
1332 
1333     auto kax_seek_pre_roll  = FindChild<KaxSeekPreRoll>(ktentry);
1334     auto kax_codec_delay    = FindChild<KaxCodecDelay>(ktentry);
1335 
1336     if (kax_seek_pre_roll)
1337       track->seek_pre_roll = timestamp_c::ns(kax_seek_pre_roll->GetValue());
1338     if (kax_codec_delay)
1339       track->codec_delay   = timestamp_c::ns(kax_codec_delay->GetValue());
1340 
1341     for (auto const &child : *ktentry) {
1342       auto kmapping = dynamic_cast<KaxBlockAdditionMapping *>(child);
1343       if (!kmapping)
1344         continue;
1345 
1346       block_addition_mapping_t mapping;
1347 
1348       mapping.id_name       = FindChildValue<KaxBlockAddIDName>(kmapping);
1349       mapping.id_type       = FindOptionalChildValue<KaxBlockAddIDType>(kmapping);
1350       mapping.id_value      = FindOptionalChildValue<KaxBlockAddIDValue>(kmapping);
1351       mapping.id_extra_data = FindChildValue<KaxBlockAddIDExtraData>(kmapping);
1352 
1353       if (mapping.is_valid())
1354         track->block_addition_mappings.push_back(mapping);
1355     }
1356 
1357     if (track->codec_id.empty()) {
1358       mxdebug_if(m_debug_track_headers, fmt::format("matroska_reader: track number {} is missing the CodecID.\n", track->track_number));
1359       m_known_bad_track_numbers[track->track_number] = true;
1360       continue;
1361     }
1362 
1363     // The variable can be empty in two cases, both of which are a
1364     // violation of the specification:
1365     //
1366     // 1. The element is present but set to a string of length 0.
1367     // 2. The element is present and set to a value that isn't a valid
1368     //    ISO 639-2 language code.
1369     //
1370     // The closest code that's semantically the closest to such a
1371     // situation is probably "und" = "undetermined".
1372     if (!track->language.is_valid())
1373       track->language = mtx::bcp47::language_c::parse("und");
1374 
1375     track->effective_language = track->language_ietf.is_valid() ? track->language_ietf : track->language;
1376 
1377     track->content_decoder.initialize(*ktentry);
1378 
1379     m_tracks.push_back(track);
1380   } // while (ktentry)
1381 
1382   io->restore_pos();
1383 }
1384 
1385 void
handle_seek_head(mm_io_c * io,EbmlElement * l0,int64_t pos)1386 kax_reader_c::handle_seek_head(mm_io_c *io,
1387                                EbmlElement *l0,
1388                                int64_t pos) {
1389   if (has_deferred_element_been_processed(dl1t_seek_head, pos))
1390     return;
1391 
1392   std::vector<int64_t> next_seek_head_positions;
1393   mtx::at_scope_exit_c restore([io]() { io->restore_pos(); });
1394 
1395   try {
1396     io->save_pos(pos);
1397 
1398     int upper_lvl_el = 0;
1399     std::shared_ptr<EbmlElement> l1(m_es->FindNextElement(EBML_CONTEXT(l0), upper_lvl_el, 0xFFFFFFFFL, true));
1400     auto *seek_head = dynamic_cast<KaxSeekHead *>(l1.get());
1401 
1402     if (!seek_head)
1403       return;
1404 
1405     EbmlElement *element_found = nullptr;
1406     upper_lvl_el               = 0;
1407 
1408     seek_head->Read(*m_es, EBML_CLASS_CONTEXT(KaxSeekHead), upper_lvl_el, element_found, true);
1409     if (!found_in(*seek_head, element_found))
1410       delete element_found;
1411 
1412     for (auto l2 : *seek_head) {
1413       if (!Is<KaxSeek>(l2))
1414         continue;
1415 
1416       auto &seek        = *static_cast<KaxSeek *>(l2);
1417       auto new_seek_pos = FindChildValue<KaxSeekPosition, int64_t>(seek, -1);
1418 
1419       if (-1 == new_seek_pos)
1420         continue;
1421 
1422       auto *k_id = FindChild<KaxSeekID>(seek);
1423       if (!k_id)
1424         continue;
1425 
1426       EbmlId id(k_id->GetBuffer(), k_id->GetSize());
1427 
1428       deferred_l1_type_e type = Is<KaxAttachments>(id) ? dl1t_attachments
1429         :                       Is<KaxChapters>(id)    ? dl1t_chapters
1430         :                       Is<KaxTags>(id)        ? dl1t_tags
1431         :                       Is<KaxTracks>(id)      ? dl1t_tracks
1432         :                       Is<KaxSeekHead>(id)    ? dl1t_seek_head
1433         :                       Is<KaxInfo>(id)        ? dl1t_info
1434         :                                                dl1t_unknown;
1435 
1436       if (dl1t_unknown == type)
1437         continue;
1438 
1439       new_seek_pos = static_cast<KaxSegment *>(l0)->GetGlobalPosition(new_seek_pos);
1440 
1441       if (dl1t_seek_head == type)
1442         next_seek_head_positions.push_back(new_seek_pos);
1443       else
1444         m_deferred_l1_positions[type].push_back(new_seek_pos);
1445     }
1446 
1447   } catch (...) {
1448     return;
1449   }
1450 
1451   for (auto new_seek_head_pos : next_seek_head_positions)
1452     handle_seek_head(io, l0, new_seek_head_pos);
1453 }
1454 
1455 void
read_headers()1456 kax_reader_c::read_headers() {
1457   if (!read_headers_internal())
1458     throw mtx::input::header_parsing_x();
1459 
1460   determine_minimum_timestamps();
1461   determine_global_timestamp_offset_to_apply();
1462   adjust_chapter_timestamps();
1463 
1464   show_demuxer_info();
1465 }
1466 
1467 void
adjust_chapter_timestamps()1468 kax_reader_c::adjust_chapter_timestamps() {
1469   if (!m_chapters)
1470     return;
1471 
1472   auto const &sync = mtx::includes(m_ti.m_timestamp_syncs, track_info_c::chapter_track_id) ? m_ti.m_timestamp_syncs[track_info_c::chapter_track_id]
1473                    : mtx::includes(m_ti.m_timestamp_syncs, track_info_c::all_tracks_id)    ? m_ti.m_timestamp_syncs[track_info_c::all_tracks_id]
1474                    :                                                                         timestamp_sync_t{};
1475 
1476   mtx::chapters::adjust_timestamps(*m_chapters, -m_global_timestamp_offset);
1477   mtx::chapters::adjust_timestamps(*m_chapters, sync.displacement, sync.factor);
1478 }
1479 
1480 void
find_level1_elements_via_analyzer()1481 kax_reader_c::find_level1_elements_via_analyzer() {
1482   try {
1483     auto start_pos = m_in->get_size() - std::min<int64_t>(m_in->get_size(), 5 * 1024 * 1024);
1484     auto analyzer  = std::make_shared<kax_analyzer_c>(m_in);
1485     auto ok        = analyzer
1486       ->set_parse_mode(kax_analyzer_c::parse_mode_full)
1487       .set_open_mode(MODE_READ)
1488       .set_parser_start_position(start_pos)
1489       .process();
1490 
1491     if (!ok)
1492       return;
1493 
1494     analyzer->with_elements(EBML_ID(KaxInfo),        [this](kax_analyzer_data_c const &data) { m_deferred_l1_positions[dl1t_info       ].push_back(data.m_pos); });
1495     analyzer->with_elements(EBML_ID(KaxTracks),      [this](kax_analyzer_data_c const &data) { m_deferred_l1_positions[dl1t_tracks     ].push_back(data.m_pos); });
1496     analyzer->with_elements(EBML_ID(KaxAttachments), [this](kax_analyzer_data_c const &data) { m_deferred_l1_positions[dl1t_attachments].push_back(data.m_pos); });
1497     analyzer->with_elements(EBML_ID(KaxChapters),    [this](kax_analyzer_data_c const &data) { m_deferred_l1_positions[dl1t_chapters   ].push_back(data.m_pos); });
1498     analyzer->with_elements(EBML_ID(KaxTags),        [this](kax_analyzer_data_c const &data) { m_deferred_l1_positions[dl1t_tags       ].push_back(data.m_pos); });
1499 
1500   } catch (...) {
1501   }
1502 }
1503 
1504 void
read_deferred_level1_elements(KaxSegment & segment)1505 kax_reader_c::read_deferred_level1_elements(KaxSegment &segment) {
1506   for (auto position : m_deferred_l1_positions[dl1t_info])
1507     read_headers_info(m_in.get(), &segment, position);
1508 
1509   for (auto position : m_deferred_l1_positions[dl1t_tracks])
1510     read_headers_tracks(m_in.get(), &segment, position);
1511 
1512   if (!m_ti.m_attach_mode_list.none())
1513     for (auto position : m_deferred_l1_positions[dl1t_attachments])
1514       handle_attachments(m_in.get(), &segment, position);
1515 
1516   for (auto position : m_deferred_l1_positions[dl1t_tags])
1517     handle_tags(m_in.get(), &segment, position);
1518 
1519   if (!m_ti.m_no_chapters)
1520     for (auto position : m_deferred_l1_positions[dl1t_chapters])
1521       handle_chapters(m_in.get(), &segment, position);
1522 
1523   handle_track_statistics_tags();
1524 
1525   if (!m_ti.m_no_global_tags)
1526     process_global_tags();
1527 }
1528 
1529 bool
read_headers_internal()1530 kax_reader_c::read_headers_internal() {
1531   // Elements for different levels
1532 
1533   auto cluster = std::shared_ptr<KaxCluster>{};
1534   try {
1535     m_es      = std::shared_ptr<EbmlStream>(new EbmlStream(*m_in));
1536     m_in_file = std::make_shared<kax_file_c>(*m_in);
1537 
1538     m_in_file->enable_reporting(!g_identifying);
1539 
1540     // Find the EbmlHead element. Must be the first one.
1541     auto l0 = std::shared_ptr<EbmlElement>(m_es->FindNextID(EBML_INFO(EbmlHead), 0xFFFFFFFFFFFFFFFFLL));
1542     if (!l0) {
1543       mxwarn(Y("matroska_reader: no EBML head found.\n"));
1544       return false;
1545     }
1546 
1547     // Don't verify its data for now.
1548     l0->SkipData(*m_es, EBML_CONTEXT(l0));
1549 
1550     // Next element must be a segment
1551     l0.reset(m_es->FindNextID(EBML_INFO(KaxSegment), 0xFFFFFFFFFFFFFFFFLL));
1552     if (!l0) {
1553       if (verbose)
1554         mxwarn(Y("matroska_reader: No segment found.\n"));
1555       return false;
1556     }
1557     if (!Is<KaxSegment>(*l0)) {
1558       if (verbose)
1559         mxwarn(Y("matroska_reader: No segment found.\n"));
1560       return false;
1561     }
1562 
1563     m_in_file->set_segment_end(*l0);
1564 
1565     // We've got our segment, so let's find the m_tracks
1566     m_tc_scale = TIMESTAMP_SCALE;
1567 
1568     while (m_in->getFilePointer() < m_in_file->get_segment_end()) {
1569       auto l1 = m_in_file->read_next_level1_element();
1570       if (!l1)
1571         break;
1572 
1573       if (Is<KaxInfo>(*l1))
1574         m_deferred_l1_positions[dl1t_info].push_back(l1->GetElementPosition());
1575 
1576       else if (Is<KaxTracks>(*l1))
1577         m_deferred_l1_positions[dl1t_tracks].push_back(l1->GetElementPosition());
1578 
1579       else if (Is<KaxAttachments>(*l1))
1580         m_deferred_l1_positions[dl1t_attachments].push_back(l1->GetElementPosition());
1581 
1582       else if (Is<KaxChapters>(*l1))
1583         m_deferred_l1_positions[dl1t_chapters].push_back(l1->GetElementPosition());
1584 
1585       else if (Is<KaxTags>(*l1))
1586         m_deferred_l1_positions[dl1t_tags].push_back(l1->GetElementPosition());
1587 
1588       else if (Is<KaxSeekHead>(*l1))
1589         handle_seek_head(m_in.get(), l0.get(), l1->GetElementPosition());
1590 
1591       else if (Is<KaxCluster>(*l1))
1592         cluster = std::static_pointer_cast<KaxCluster>(l1);
1593 
1594       else
1595         l1->SkipData(*m_es, EBML_CONTEXT(l1));
1596 
1597       if (cluster)              // we've found the first cluster, so get out
1598         break;
1599 
1600       auto in_parent = !l0->IsFiniteSize() || (m_in->getFilePointer() < (l0->GetElementPosition() + l0->HeadSize() + l0->GetSize()));
1601 
1602       if (!in_parent)
1603         break;
1604 
1605       l1->SkipData(*m_es, EBML_CONTEXT(l1));
1606 
1607     } // while (l1)
1608 
1609     if (m_handled_l1_positions[dl1t_seek_head].empty() || debugging_c::requested("kax_reader_use_analyzer"))
1610       find_level1_elements_via_analyzer();
1611 
1612     read_deferred_level1_elements(static_cast<KaxSegment &>(*l0));
1613 
1614   } catch (...) {
1615     mxwarn(fmt::format("{0} {1} {2}\n",
1616                        fmt::format(Y("{0}: an unknown exception occurred."), "kax_reader_c::read_headers_internal()"),
1617                        Y("This usually indicates a damaged file structure."), Y("The file will not be processed further.")));
1618   }
1619 
1620   auto cluster_pos = cluster ? cluster->GetElementPosition() : m_in->get_size();
1621   m_in->setFilePointer(cluster_pos);
1622 
1623   verify_tracks();
1624 
1625   m_in->setFilePointer(cluster_pos);
1626 
1627   return true;
1628 }
1629 
1630 void
process_global_tags()1631 kax_reader_c::process_global_tags() {
1632   if (!m_tags || g_identifying)
1633     return;
1634 
1635   for (auto tag : *m_tags)
1636     add_tags(static_cast<KaxTag &>(*tag));
1637 
1638   m_tags->RemoveAll();
1639 }
1640 
1641 void
init_passthrough_packetizer(kax_track_t * t,track_info_c & nti)1642 kax_reader_c::init_passthrough_packetizer(kax_track_t *t,
1643                                           track_info_c &nti) {
1644   mxinfo_tid(m_ti.m_fname, t->tnum, fmt::format(Y("Using the generic output module for track type '{0}'.\n"), map_track_type_string(t->type)));
1645 
1646   auto packetizer                 = new passthrough_packetizer_c(this, nti);
1647   t->ptzr                         = add_packetizer(packetizer);
1648   t->ptzr_ptr                     = packetizer;
1649   t->passthrough                  = true;
1650   m_ptzr_to_track_map[packetizer] = t;
1651 
1652   packetizer->set_track_type(map_track_type(t->type));
1653   packetizer->set_codec_id(t->codec_id);
1654   packetizer->set_codec_private(t->private_data);
1655   packetizer->set_codec_name(t->codec_name);
1656 
1657   if (t->default_duration)
1658     packetizer->set_track_default_duration(t->default_duration);
1659   if (t->seek_pre_roll.valid())
1660     packetizer->set_track_seek_pre_roll(t->seek_pre_roll);
1661 
1662   t->handle_packetizer_block_addition_mapping();
1663 
1664   if ('v' == t->type) {
1665     packetizer->set_video_pixel_width(t->v_width);
1666     packetizer->set_video_pixel_height(t->v_height);
1667 
1668     t->handle_packetizer_display_dimensions();
1669     t->handle_packetizer_pixel_cropping();
1670     t->handle_packetizer_colour();
1671     t->handle_packetizer_field_order();
1672     t->handle_packetizer_stereo_mode();
1673 
1674     if (CUE_STRATEGY_UNSPECIFIED == packetizer->get_cue_creation())
1675       packetizer->set_cue_creation(CUE_STRATEGY_IFRAMES);
1676 
1677   } else if ('a' == t->type) {
1678     packetizer->set_audio_sampling_freq(t->a_sfreq);
1679     packetizer->set_audio_channels(t->a_channels);
1680     if (0 != t->a_bps)
1681       packetizer->set_audio_bit_depth(t->a_bps);
1682     if (0.0 != t->a_osfreq)
1683       packetizer->set_audio_output_sampling_freq(t->a_osfreq);
1684 
1685   } else {
1686     // Nothing to do for subs, I guess.
1687   }
1688 
1689 }
1690 
1691 void
set_packetizer_headers(kax_track_t * t)1692 kax_reader_c::set_packetizer_headers(kax_track_t *t) {
1693   if (m_appending)
1694     return;
1695 
1696   if (!ptzr(t->ptzr).m_ti.m_default_track.has_value())
1697     ptzr(t->ptzr).set_track_default_flag(t->default_track);
1698 
1699   if (t->forced_track && !ptzr(t->ptzr).m_ti.m_forced_track.has_value())
1700     ptzr(t->ptzr).set_track_forced_flag(true);
1701 
1702   if (t->hearing_impaired_flag.has_value() && !ptzr(t->ptzr).m_ti.m_hearing_impaired_flag.has_value())
1703     ptzr(t->ptzr).set_hearing_impaired_flag(*t->hearing_impaired_flag);
1704 
1705   if (t->visual_impaired_flag.has_value() && !ptzr(t->ptzr).m_ti.m_visual_impaired_flag.has_value())
1706     ptzr(t->ptzr).set_visual_impaired_flag(*t->visual_impaired_flag);
1707 
1708   if (t->text_descriptions_flag.has_value() && !ptzr(t->ptzr).m_ti.m_text_descriptions_flag.has_value())
1709     ptzr(t->ptzr).set_text_descriptions_flag(*t->text_descriptions_flag);
1710 
1711   if (t->original_flag.has_value() && !ptzr(t->ptzr).m_ti.m_original_flag.has_value())
1712     ptzr(t->ptzr).set_original_flag(*t->original_flag);
1713 
1714   if (t->commentary_flag.has_value() && !ptzr(t->ptzr).m_ti.m_commentary_flag.has_value())
1715     ptzr(t->ptzr).set_commentary_flag(*t->commentary_flag);
1716 
1717   if (!ptzr(t->ptzr).m_ti.m_enabled_track.has_value())
1718     ptzr(t->ptzr).set_track_enabled_flag(static_cast<bool>(t->enabled_track));
1719 
1720   if ((0 != t->track_uid) && !ptzr(t->ptzr).set_uid(t->track_uid))
1721     mxwarn_fn(m_ti.m_fname, fmt::format(Y("Could not keep a track's UID {0} because it is already allocated for another track. A new random UID will be allocated automatically.\n"), t->track_uid));
1722 
1723   ptzr(t->ptzr).set_codec_name(t->codec_name);
1724   ptzr(t->ptzr).set_source_id(t->source_id);
1725 
1726   if ((t->type == 'a') && (0 != t->a_bps))
1727     ptzr(t->ptzr).set_audio_bit_depth(t->a_bps);
1728 
1729   t->handle_packetizer_block_addition_mapping();
1730 }
1731 
1732 void
create_video_packetizer(kax_track_t * t,track_info_c & nti)1733 kax_reader_c::create_video_packetizer(kax_track_t *t,
1734                                       track_info_c &nti) {
1735   if (t->codec.is(codec_c::type_e::V_MPEG4_P10) && t->ms_compat && !mtx::hacks::is_engaged(mtx::hacks::ALLOW_AVC_IN_VFW_MODE))
1736     create_avc_es_video_packetizer(t, nti);
1737 
1738   else if (t->codec.is(codec_c::type_e::V_MPEG12)) {
1739     int version = t->codec_id[6] - '0';
1740     set_track_packetizer(t, new mpeg1_2_video_packetizer_c(this, nti, version, t->default_duration, t->v_width, t->v_height, t->v_dwidth, t->v_dheight, true));
1741     show_packetizer_info(t->tnum, *t->ptzr_ptr);
1742 
1743   } else if (t->codec.is(codec_c::type_e::V_MPEGH_P2))
1744     create_hevc_video_packetizer(t, nti);
1745 
1746   else if (t->codec.is(codec_c::type_e::V_MPEG4_P2)) {
1747     bool is_native = (t->codec_id == MKV_V_MPEG4_SP) || (t->codec_id == MKV_V_MPEG4_AP) || (t->codec_id == MKV_V_MPEG4_ASP);
1748     set_track_packetizer(t, new mpeg4_p2_video_packetizer_c(this, nti, t->default_duration, t->v_width, t->v_height, is_native));
1749     show_packetizer_info(t->tnum, *t->ptzr_ptr);
1750 
1751   } else if (t->codec.is(codec_c::type_e::V_MPEG4_P10))
1752     create_avc_video_packetizer(t, nti);
1753 
1754   else if (t->codec.is(codec_c::type_e::V_THEORA)) {
1755     set_track_packetizer(t, new theora_video_packetizer_c(this, nti, t->default_duration, t->v_width, t->v_height));
1756     show_packetizer_info(t->tnum, *t->ptzr_ptr);
1757 
1758   } else if (t->codec.is(codec_c::type_e::V_DIRAC)) {
1759     set_track_packetizer(t, new dirac_video_packetizer_c(this, nti));
1760     show_packetizer_info(t->tnum, *t->ptzr_ptr);
1761 
1762   } else if (t->codec.is(codec_c::type_e::V_AV1))
1763     create_av1_video_packetizer(t, nti);
1764 
1765   else if (t->codec.is(codec_c::type_e::V_PRORES))
1766     create_prores_video_packetizer(*t, nti);
1767 
1768   else if (t->codec.is(codec_c::type_e::V_VP8) || t->codec.is(codec_c::type_e::V_VP9)) {
1769     set_track_packetizer(t, new vpx_video_packetizer_c(this, nti, t->codec.get_type()));
1770     show_packetizer_info(t->tnum, *t->ptzr_ptr);
1771     t->handle_packetizer_pixel_dimensions();
1772     t->handle_packetizer_default_duration();
1773 
1774   } else if (t->codec.is(codec_c::type_e::V_VC1))
1775     create_vc1_video_packetizer(t, nti);
1776 
1777   else if (t->ms_compat) {
1778     set_track_packetizer(t, new video_for_windows_packetizer_c(this, nti, t->default_duration, t->v_width, t->v_height));
1779     show_packetizer_info(t->tnum, *t->ptzr_ptr);
1780 
1781   } else {
1782     set_track_packetizer(t, new generic_video_packetizer_c(this, nti, t->codec_id.c_str(), t->default_duration, t->v_width, t->v_height));
1783     show_packetizer_info(t->tnum, *t->ptzr_ptr);
1784   }
1785 
1786   t->handle_packetizer_display_dimensions();
1787   t->handle_packetizer_pixel_cropping();
1788   t->handle_packetizer_colour();
1789   t->handle_packetizer_field_order();
1790   t->handle_packetizer_stereo_mode();
1791   t->handle_packetizer_codec_delay();
1792 }
1793 
1794 void
create_aac_audio_packetizer(kax_track_t * t,track_info_c & nti)1795 kax_reader_c::create_aac_audio_packetizer(kax_track_t *t,
1796                                           track_info_c &nti) {
1797   // A_AAC/MPEG2/MAIN
1798   // 0123456789012345
1799   mtx::aac::audio_config_t audio_config{};
1800 
1801   audio_config.sample_rate = t->a_sfreq;
1802   audio_config.channels    = t->a_channels;
1803   int detected_profile     = mtx::aac::PROFILE_MAIN;
1804 
1805   if (!t->ms_compat) {
1806     if (t->private_data && (2 <= t->private_data->get_size())) {
1807       auto parsed_audio_config = mtx::aac::parse_audio_specific_config(t->private_data->get_buffer(), t->private_data->get_size());
1808       if (!parsed_audio_config)
1809         mxerror_tid(m_ti.m_fname, t->tnum, Y("Malformed AAC codec initialization data found.\n"));
1810 
1811       audio_config           = *parsed_audio_config;
1812       detected_profile       = audio_config.profile;
1813       if (audio_config.sbr)
1814         audio_config.profile = mtx::aac::PROFILE_SBR;
1815 
1816     } else {
1817       int id = 0, profile = 0;
1818       if (!mtx::aac::parse_codec_id(t->codec_id, id, profile))
1819         mxerror_tid(m_ti.m_fname, t->tnum, fmt::format(Y("Malformed codec id '{0}'.\n"), t->codec_id));
1820       audio_config.profile = profile;
1821     }
1822 
1823   } else {
1824     auto parsed_audio_config = mtx::aac::parse_audio_specific_config(t->private_data->get_buffer() + sizeof(alWAVEFORMATEX), t->private_data->get_size() - sizeof(alWAVEFORMATEX));
1825     if (!parsed_audio_config)
1826       mxerror_tid(m_ti.m_fname, t->tnum, Y("Malformed AAC codec initialization data found.\n"));
1827 
1828     audio_config           = *parsed_audio_config;
1829     detected_profile       = audio_config.profile;
1830     if (audio_config.sbr)
1831       audio_config.profile = mtx::aac::PROFILE_SBR;
1832   }
1833 
1834   if ((mtx::includes(m_ti.m_all_aac_is_sbr, t->tnum) &&  m_ti.m_all_aac_is_sbr[t->tnum]) || (mtx::includes(m_ti.m_all_aac_is_sbr, -1) &&  m_ti.m_all_aac_is_sbr[-1]))
1835     audio_config.profile = mtx::aac::PROFILE_SBR;
1836 
1837   if ((mtx::includes(m_ti.m_all_aac_is_sbr, t->tnum) && !m_ti.m_all_aac_is_sbr[t->tnum]) || (mtx::includes(m_ti.m_all_aac_is_sbr, -1) && !m_ti.m_all_aac_is_sbr[-1]))
1838     audio_config.profile = detected_profile;
1839 
1840   set_track_packetizer(t, new aac_packetizer_c(this, nti, audio_config, aac_packetizer_c::headerless));
1841   show_packetizer_info(t->tnum, *t->ptzr_ptr);
1842 }
1843 
1844 void
create_ac3_audio_packetizer(kax_track_t * t,track_info_c & nti)1845 kax_reader_c::create_ac3_audio_packetizer(kax_track_t *t,
1846                                           track_info_c &nti) {
1847   unsigned int bsid = t->codec_id == "A_AC3/BSID9"  ?  9
1848                     : t->codec_id == "A_AC3/BSID10" ? 10
1849                     : t->codec_id == MKV_A_EAC3     ? 16
1850                     :                                  0;
1851 
1852   set_track_packetizer(t, new ac3_packetizer_c(this, nti, t->a_sfreq, t->a_channels, bsid));
1853   show_packetizer_info(t->tnum, *t->ptzr_ptr);
1854 }
1855 
1856 void
create_alac_audio_packetizer(kax_track_t * t,track_info_c & nti)1857 kax_reader_c::create_alac_audio_packetizer(kax_track_t *t,
1858                                           track_info_c &nti) {
1859   set_track_packetizer(t, new alac_packetizer_c(this, nti, t->private_data, t->a_sfreq, t->a_channels));
1860   show_packetizer_info(t->tnum, *t->ptzr_ptr);
1861 }
1862 
1863 void
create_dts_audio_packetizer(kax_track_t * t,track_info_c & nti)1864 kax_reader_c::create_dts_audio_packetizer(kax_track_t *t,
1865                                           track_info_c &nti) {
1866   set_track_packetizer(t, new dts_packetizer_c(this, nti, t->dts_header));
1867   show_packetizer_info(t->tnum, *t->ptzr_ptr);
1868 }
1869 
1870 #if defined(HAVE_FLAC_FORMAT_H)
1871 void
create_flac_audio_packetizer(kax_track_t * t,track_info_c & nti)1872 kax_reader_c::create_flac_audio_packetizer(kax_track_t *t,
1873                                            track_info_c &nti) {
1874   nti.m_private_data.reset();
1875 
1876   unsigned int offset = t->ms_compat ? sizeof(alWAVEFORMATEX) : 0u;
1877   set_track_packetizer(t, new flac_packetizer_c(this, nti, t->private_data->get_buffer() + offset, t->private_data->get_size() - offset));
1878 
1879   show_packetizer_info(t->tnum, *t->ptzr_ptr);
1880 }
1881 
1882 #endif  // HAVE_FLAC_FORMAT_H
1883 
1884 void
create_av1_video_packetizer(kax_track_t * t,track_info_c & nti)1885 kax_reader_c::create_av1_video_packetizer(kax_track_t *t,
1886                                           track_info_c &nti) {
1887   if (   (m_writing_app     == "mkvmerge")
1888       && (m_writing_app_ver != -1)
1889       && (m_writing_app_ver <= writing_app_ver(28, 0, 0, 0))) {
1890     // mkvmerge 28.0.0 created invalid av1C CodecPrivate data. Let's rebuild it.
1891     nti.m_private_data.reset();
1892   }
1893 
1894   set_track_packetizer(t, new av1_video_packetizer_c(this, nti));
1895   show_packetizer_info(t->tnum, *t->ptzr_ptr);
1896   t->handle_packetizer_pixel_dimensions();
1897   t->handle_packetizer_default_duration();
1898 }
1899 
1900 void
create_hevc_es_video_packetizer(kax_track_t * t,track_info_c & nti)1901 kax_reader_c::create_hevc_es_video_packetizer(kax_track_t *t,
1902                                               track_info_c &nti) {
1903   auto packetizer = new hevc_es_video_packetizer_c(this, nti);
1904   set_track_packetizer(t, packetizer);
1905 
1906   packetizer->set_video_pixel_dimensions(t->v_width, t->v_height);
1907 
1908   show_packetizer_info(t->tnum, *t->ptzr_ptr);
1909 }
1910 
1911 void
create_hevc_video_packetizer(kax_track_t * t,track_info_c & nti)1912 kax_reader_c::create_hevc_video_packetizer(kax_track_t *t,
1913                                            track_info_c &nti) {
1914   if (t->ms_compat || !nti.m_private_data || !nti.m_private_data->get_size()) {
1915     create_hevc_es_video_packetizer(t, nti);
1916     return;
1917   }
1918 
1919   auto ptzr = new hevc_video_packetizer_c(this, nti, t->default_duration, t->v_width, t->v_height);
1920   ptzr->set_source_timestamp_resolution(m_tc_scale);
1921 
1922   set_track_packetizer(t, ptzr);
1923   show_packetizer_info(t->tnum, *t->ptzr_ptr);
1924 }
1925 
1926 void
create_mp3_audio_packetizer(kax_track_t * t,track_info_c & nti)1927 kax_reader_c::create_mp3_audio_packetizer(kax_track_t *t,
1928                                           track_info_c &nti) {
1929   set_track_packetizer(t, new mp3_packetizer_c(this, nti, t->a_sfreq, t->a_channels, true));
1930   show_packetizer_info(t->tnum, *t->ptzr_ptr);
1931 }
1932 
1933 void
create_opus_audio_packetizer(kax_track_t * t,track_info_c & nti)1934 kax_reader_c::create_opus_audio_packetizer(kax_track_t *t,
1935                                            track_info_c &nti) {
1936   set_track_packetizer(t, new opus_packetizer_c(this, nti));
1937   show_packetizer_info(t->tnum, *t->ptzr_ptr);
1938 
1939   if (!m_opus_experimental_warning_shown && (t->codec_id == std::string{MKV_A_OPUS} + "/EXPERIMENTAL")) {
1940     mxwarn(fmt::format(Y("'{0}': You're copying an Opus track that was written in experimental mode. "
1941                          "The resulting track will be written in final mode, but one detail cannot be recovered from a track written in experimental mode: the end trimming. "
1942                          "This means that a decoder might output a few samples more than originally intended. "
1943                          "You should re-multiplex from the original Opus file if possible.\n"),
1944                        m_ti.m_fname));
1945     m_opus_experimental_warning_shown = true;
1946   }
1947 }
1948 
1949 void
create_pcm_audio_packetizer(kax_track_t * t,track_info_c & nti)1950 kax_reader_c::create_pcm_audio_packetizer(kax_track_t *t,
1951                                           track_info_c &nti) {
1952   auto type = t->codec_id == MKV_A_PCM_FLOAT ? pcm_packetizer_c::ieee_float
1953             : t->codec_id == MKV_A_PCM_BE    ? pcm_packetizer_c::big_endian_integer
1954             :                                  pcm_packetizer_c::little_endian_integer;
1955   set_track_packetizer(t, new pcm_packetizer_c(this, nti, t->a_sfreq, t->a_channels, t->a_bps, type));
1956   show_packetizer_info(t->tnum, *t->ptzr_ptr);
1957 }
1958 
1959 void
create_truehd_audio_packetizer(kax_track_t * t,track_info_c & nti)1960 kax_reader_c::create_truehd_audio_packetizer(kax_track_t *t,
1961                                              track_info_c &nti) {
1962   nti.m_private_data.reset();
1963   set_track_packetizer(t, new truehd_packetizer_c(this, nti, t->codec.is(codec_c::type_e::A_TRUEHD) ? mtx::truehd::frame_t::truehd : mtx::truehd::frame_t::mlp, t->a_sfreq, t->a_channels));
1964   show_packetizer_info(t->tnum, *t->ptzr_ptr);
1965 }
1966 
1967 void
create_tta_audio_packetizer(kax_track_t * t,track_info_c & nti)1968 kax_reader_c::create_tta_audio_packetizer(kax_track_t *t,
1969                                           track_info_c &nti) {
1970   set_track_packetizer(t, new tta_packetizer_c(this, nti, t->a_channels, t->a_bps, t->a_sfreq));
1971   show_packetizer_info(t->tnum, *t->ptzr_ptr);
1972 }
1973 
1974 void
create_vorbis_audio_packetizer(kax_track_t * t,track_info_c & nti)1975 kax_reader_c::create_vorbis_audio_packetizer(kax_track_t *t,
1976                                              track_info_c &nti) {
1977   set_track_packetizer(t, new vorbis_packetizer_c(this, nti, t->headers));
1978   show_packetizer_info(t->tnum, *t->ptzr_ptr);
1979 }
1980 
1981 void
create_wavpack_audio_packetizer(kax_track_t * t,track_info_c & nti)1982 kax_reader_c::create_wavpack_audio_packetizer(kax_track_t *t,
1983                                               track_info_c &nti) {
1984   nti.m_private_data = t->private_data;
1985 
1986   mtx::wavpack::meta_t meta;
1987   meta.bits_per_sample = t->a_bps;
1988   meta.channel_count   = t->a_channels;
1989   meta.sample_rate     = t->a_sfreq;
1990   meta.has_correction  = t->max_blockadd_id != 0;
1991 
1992   if (0 < t->default_duration)
1993     meta.samples_per_block = t->a_sfreq * t->default_duration / 1'000'000'000.0;
1994 
1995   set_track_packetizer(t, new wavpack_packetizer_c(this, nti, meta));
1996 
1997   show_packetizer_info(t->tnum, *t->ptzr_ptr);
1998 }
1999 
2000 void
create_audio_packetizer(kax_track_t * t,track_info_c & nti)2001 kax_reader_c::create_audio_packetizer(kax_track_t *t,
2002                                       track_info_c &nti) {
2003   if (t->codec.is(codec_c::type_e::A_PCM))
2004     create_pcm_audio_packetizer(t, nti);
2005 
2006   else if (t->codec.is(codec_c::type_e::A_MP2) || t->codec.is(codec_c::type_e::A_MP3))
2007     create_mp3_audio_packetizer(t, nti);
2008 
2009   else if (t->codec.is(codec_c::type_e::A_AC3))
2010     create_ac3_audio_packetizer(t, nti);
2011 
2012   else if (t->codec.is(codec_c::type_e::A_DTS))
2013     create_dts_audio_packetizer(t, nti);
2014 
2015   else if (t->codec.is(codec_c::type_e::A_VORBIS))
2016     create_vorbis_audio_packetizer(t, nti);
2017 
2018   else if (t->codec.is(codec_c::type_e::A_ALAC))
2019     create_alac_audio_packetizer(t, nti);
2020 
2021   else if (t->codec.is(codec_c::type_e::A_AAC))
2022     create_aac_audio_packetizer(t, nti);
2023 
2024 #if defined(HAVE_FLAC_FORMAT_H)
2025   else if (t->codec.is(codec_c::type_e::A_FLAC))
2026     create_flac_audio_packetizer(t, nti);
2027 #endif
2028 
2029   else if (t->codec.is(codec_c::type_e::A_OPUS))
2030     create_opus_audio_packetizer(t, nti);
2031 
2032   else if (t->codec.is(codec_c::type_e::A_TRUEHD))
2033     create_truehd_audio_packetizer(t, nti);
2034 
2035   else if (t->codec.is(codec_c::type_e::A_TTA))
2036     create_tta_audio_packetizer(t, nti);
2037 
2038   else if (t->codec.is(codec_c::type_e::A_WAVPACK4))
2039     create_wavpack_audio_packetizer(t, nti);
2040 
2041   else
2042     init_passthrough_packetizer(t, nti);
2043 
2044   t->handle_packetizer_output_sampling_freq();
2045   t->handle_packetizer_codec_delay();
2046 }
2047 
2048 void
create_dvbsub_subtitle_packetizer(kax_track_t & t,track_info_c & nti)2049 kax_reader_c::create_dvbsub_subtitle_packetizer(kax_track_t &t,
2050                                                 track_info_c &nti) {
2051   if (t.private_data->get_size() == 4) {
2052     // The subtitling type byte is missing. Add it. From ETSI EN 300 468 table 26:
2053     // 0x10 = DVB subtitles (normal) with no monitor aspect ratio criticality
2054 
2055     t.private_data->resize(5);
2056     t.private_data->get_buffer()[4] = 0x10;
2057   }
2058 
2059   set_track_packetizer(&t, new dvbsub_packetizer_c(this, nti, t.private_data));
2060   show_packetizer_info(t.tnum, *t.ptzr_ptr);
2061   t.sub_type = 'p';
2062 }
2063 
2064 void
create_subtitle_packetizer(kax_track_t * t,track_info_c & nti)2065 kax_reader_c::create_subtitle_packetizer(kax_track_t *t,
2066                                          track_info_c &nti) {
2067   if (t->codec.is(codec_c::type_e::S_VOBSUB)) {
2068     set_track_packetizer(t, new vobsub_packetizer_c(this, nti));
2069     show_packetizer_info(t->tnum, *t->ptzr_ptr);
2070 
2071     t->sub_type = 'v';
2072 
2073   } else if (t->codec.is(codec_c::type_e::S_DVBSUB))
2074     create_dvbsub_subtitle_packetizer(*t, nti);
2075 
2076   else if (t->codec.is(codec_c::type_e::S_WEBVTT)) {
2077     set_track_packetizer(t, new webvtt_packetizer_c(this, nti));
2078     show_packetizer_info(t->tnum, *t->ptzr_ptr);
2079 
2080     t->sub_type = 't';
2081 
2082   } else if (balg::starts_with(t->codec_id, "S_TEXT") || (t->codec_id == "S_SSA") || (t->codec_id == "S_ASS")) {
2083     std::string new_codec_id = ((t->codec_id == "S_SSA") || (t->codec_id == "S_ASS")) ? "S_TEXT/"s + std::string(&t->codec_id[2]) : t->codec_id;
2084 
2085     auto recoding_requested = mtx::includes(m_ti.m_sub_charsets, t->tnum) || mtx::includes(m_ti.m_sub_charsets, t->tnum);
2086 
2087     if (codec_c::look_up(new_codec_id).get_type() == codec_c::type_e::S_SSA_ASS)
2088       set_track_packetizer(t, new ssa_packetizer_c(this, nti, new_codec_id.c_str(), recoding_requested));
2089     else
2090       set_track_packetizer(t, new textsubs_packetizer_c(this, nti, new_codec_id.c_str(), recoding_requested));
2091 
2092     show_packetizer_info(t->tnum, *t->ptzr_ptr);
2093 
2094     t->sub_type = 't';
2095 
2096   } else if (t->codec.is(codec_c::type_e::S_KATE)) {
2097     set_track_packetizer(t, new kate_packetizer_c(this, nti));
2098     show_packetizer_info(t->tnum, *t->ptzr_ptr);
2099     t->sub_type = 'k';
2100 
2101   } else if (t->codec.is(codec_c::type_e::S_HDMV_PGS)) {
2102     set_track_packetizer(t, new hdmv_pgs_packetizer_c(this, nti));
2103     show_packetizer_info(t->tnum, *t->ptzr_ptr);
2104     t->sub_type = 'p';
2105 
2106   } else if (t->codec.is(codec_c::type_e::S_HDMV_TEXTST)) {
2107     set_track_packetizer(t, new hdmv_textst_packetizer_c(this, nti, t->private_data));
2108     show_packetizer_info(t->tnum, *t->ptzr_ptr);
2109     t->sub_type = 'p';
2110 
2111   } else
2112     init_passthrough_packetizer(t, nti);
2113 
2114 }
2115 
2116 void
create_button_packetizer(kax_track_t * t,track_info_c & nti)2117 kax_reader_c::create_button_packetizer(kax_track_t *t,
2118                                        track_info_c &nti) {
2119   if (!t->codec.is(codec_c::type_e::B_VOBBTN)) {
2120     init_passthrough_packetizer(t, nti);
2121     return;
2122   }
2123 
2124   nti.m_private_data.reset();
2125   t->sub_type = 'b';
2126 
2127   set_track_packetizer(t, new vobbtn_packetizer_c(this, nti, t->v_width, t->v_height));
2128   show_packetizer_info(t->tnum, *t->ptzr_ptr);
2129 }
2130 
2131 void
create_packetizer(int64_t tid)2132 kax_reader_c::create_packetizer(int64_t tid) {
2133   kax_track_t *t = m_tracks[tid].get();
2134 
2135   if ((-1 != t->ptzr) || !t->ok || !demuxing_requested(t->type, t->tnum, t->effective_language))
2136     return;
2137 
2138   track_info_c nti(m_ti);
2139   nti.m_private_data = t->private_data ? t->private_data->clone() : memory_cptr{};
2140   nti.m_id           = t->tnum; // ID for this track.
2141 
2142   if (!nti.m_language.is_valid())
2143     nti.m_language   = t->effective_language;
2144   if (nti.m_track_name == "")
2145     nti.m_track_name = t->track_name;
2146   if (t->tags && demuxing_requested('T', t->tnum))
2147     nti.m_tags       = clone(t->tags);
2148 
2149   if (mtx::hacks::is_engaged(mtx::hacks::FORCE_PASSTHROUGH_PACKETIZER)) {
2150     init_passthrough_packetizer(t, nti);
2151     set_packetizer_headers(t);
2152 
2153     return;
2154   }
2155 
2156   switch (t->type) {
2157     case 'v':
2158       create_video_packetizer(t, nti);
2159       break;
2160 
2161     case 'a':
2162       create_audio_packetizer(t, nti);
2163       break;
2164 
2165     case 's':
2166       create_subtitle_packetizer(t, nti);
2167       break;
2168 
2169     case 'b':
2170       create_button_packetizer(t, nti);
2171       break;
2172 
2173     default:
2174       mxerror_tid(m_ti.m_fname, t->tnum, Y("Unsupported track type for this track.\n"));
2175       break;
2176   }
2177 
2178   set_packetizer_headers(t);
2179   m_ptzr_to_track_map[ &ptzr(t->ptzr) ] = t;
2180 }
2181 
2182 void
create_packetizers()2183 kax_reader_c::create_packetizers() {
2184   m_in->save_pos();
2185 
2186   for (auto &track : m_tracks)
2187     create_packetizer(track->tnum);
2188 
2189   if (!g_segment_title_set && !m_title.empty()) {
2190     g_segment_title     = m_title;
2191     g_segment_title_set = true;
2192   }
2193 
2194   m_in->restore_pos();
2195 }
2196 
2197 void
create_avc_es_video_packetizer(kax_track_t * t,track_info_c & nti)2198 kax_reader_c::create_avc_es_video_packetizer(kax_track_t *t,
2199                                              track_info_c &nti) {
2200   auto ptzr = new avc_es_video_packetizer_c(this, nti);
2201   set_track_packetizer(t, ptzr);
2202 
2203   ptzr->set_video_pixel_dimensions(t->v_width, t->v_height);
2204 
2205   show_packetizer_info(t->tnum, *t->ptzr_ptr);
2206 }
2207 
2208 void
create_avc_video_packetizer(kax_track_t * t,track_info_c & nti)2209 kax_reader_c::create_avc_video_packetizer(kax_track_t *t,
2210                                           track_info_c &nti) {
2211   if (!nti.m_private_data || !nti.m_private_data->get_size()) {
2212     create_avc_es_video_packetizer(t, nti);
2213     return;
2214   }
2215 
2216   set_track_packetizer(t, new avc_video_packetizer_c(this, nti, t->default_duration, t->v_width, t->v_height));
2217   show_packetizer_info(t->tnum, *t->ptzr_ptr);
2218 }
2219 
2220 void
create_prores_video_packetizer(kax_track_t & t,track_info_c & nti)2221 kax_reader_c::create_prores_video_packetizer(kax_track_t &t,
2222                                              track_info_c &nti) {
2223   set_track_packetizer(&t, new prores_video_packetizer_c{this, nti, t.default_duration, static_cast<int>(t.v_width), static_cast<int>(t.v_height)});
2224   show_packetizer_info(t.tnum, *t.ptzr_ptr);
2225 }
2226 
2227 void
create_vc1_video_packetizer(kax_track_t * t,track_info_c & nti)2228 kax_reader_c::create_vc1_video_packetizer(kax_track_t *t,
2229                                           track_info_c &nti) {
2230   read_first_frames(t, 1);
2231   if (   !t->first_frames_data.empty()
2232       && (4 <= t->first_frames_data[0]->get_size())
2233       && !mtx::vc1::is_marker(get_uint32_be(t->first_frames_data[0]->get_buffer()))) {
2234     init_passthrough_packetizer(t, nti);
2235     return;
2236   }
2237 
2238   set_track_packetizer(t, new vc1_video_packetizer_c(this, nti));
2239   show_packetizer_info(t->tnum, *t->ptzr_ptr);
2240 
2241   if (t->private_data && (sizeof(alBITMAPINFOHEADER) < t->private_data->get_size()))
2242     t->ptzr_ptr->process(std::make_shared<packet_t>(memory_c::borrow(t->private_data->get_buffer() + sizeof(alBITMAPINFOHEADER), t->private_data->get_size() - sizeof(alBITMAPINFOHEADER))));
2243 }
2244 
2245 void
read_first_frames(kax_track_t * t,unsigned num_wanted)2246 kax_reader_c::read_first_frames(kax_track_t *t,
2247                                 unsigned num_wanted) {
2248   if (t->first_frames_data.size() >= num_wanted)
2249     return;
2250 
2251   std::map<int64_t, unsigned int> frames_by_track_id;
2252 
2253   try {
2254     while (true) {
2255       auto cluster = m_in_file->read_next_cluster();
2256       if (!cluster)
2257         return;
2258 
2259       KaxClusterTimecode *ctc = static_cast<KaxClusterTimecode *> (cluster->FindFirstElt(EBML_INFO(KaxClusterTimecode), false));
2260       if (ctc)
2261         cluster->InitTimecode(ctc->GetValue(), m_tc_scale);
2262 
2263       size_t bgidx;
2264       for (bgidx = 0; bgidx < cluster->ListSize(); bgidx++) {
2265         if (Is<KaxSimpleBlock>((*cluster)[bgidx])) {
2266           KaxSimpleBlock *block_simple = static_cast<KaxSimpleBlock *>((*cluster)[bgidx]);
2267 
2268           block_simple->SetParent(*cluster);
2269           kax_track_t *block_track = find_track_by_num(block_simple->TrackNum());
2270 
2271           if (!block_track || (0 == block_simple->NumberFrames()))
2272             continue;
2273 
2274           for (int frame_idx = 0, num_frames = block_simple->NumberFrames(); frame_idx < num_frames; ++frame_idx) {
2275             frames_by_track_id[ block_simple->TrackNum() ]++;
2276 
2277             if (frames_by_track_id[ block_simple->TrackNum() ] <= block_track->first_frames_data.size())
2278               continue;
2279 
2280             DataBuffer &data_buffer = block_simple->GetBuffer(frame_idx);
2281             block_track->first_frames_data.push_back(memory_c::borrow(data_buffer.Buffer(), data_buffer.Size()));
2282             block_track->content_decoder.reverse(block_track->first_frames_data.back(), CONTENT_ENCODING_SCOPE_BLOCK);
2283             block_track->first_frames_data.back()->take_ownership();
2284           }
2285 
2286         } else if (Is<KaxBlockGroup>((*cluster)[bgidx])) {
2287           KaxBlockGroup *block_group = static_cast<KaxBlockGroup *>((*cluster)[bgidx]);
2288           KaxBlock *block            = static_cast<KaxBlock *>(block_group->FindFirstElt(EBML_INFO(KaxBlock), false));
2289 
2290           if (!block)
2291             continue;
2292 
2293           block->SetParent(*cluster);
2294           kax_track_t *block_track = find_track_by_num(block->TrackNum());
2295 
2296           if (!block_track || (0 == block->NumberFrames()))
2297             continue;
2298 
2299           for (int frame_idx = 0, num_frames = block->NumberFrames(); frame_idx < num_frames; ++frame_idx) {
2300             frames_by_track_id[ block->TrackNum() ]++;
2301 
2302             if (frames_by_track_id[ block->TrackNum() ] <= block_track->first_frames_data.size())
2303               continue;
2304 
2305             DataBuffer &data_buffer = block->GetBuffer(frame_idx);
2306             block_track->first_frames_data.push_back(memory_cptr(memory_c::borrow(data_buffer.Buffer(), data_buffer.Size())));
2307             block_track->content_decoder.reverse(block_track->first_frames_data.back(), CONTENT_ENCODING_SCOPE_BLOCK);
2308             block_track->first_frames_data.back()->take_ownership();
2309           }
2310         }
2311       }
2312 
2313       if (t->first_frames_data.size() >= num_wanted)
2314         break;
2315     }
2316   } catch (...) {
2317   }
2318 }
2319 
2320 file_status_e
read(generic_packetizer_c * requested_ptzr,bool force)2321 kax_reader_c::read(generic_packetizer_c *requested_ptzr,
2322                    bool force) {
2323   if (m_tracks.empty() || (FILE_STATUS_DONE == m_file_status))
2324     return FILE_STATUS_DONE;
2325 
2326   auto num_queued_bytes = get_queued_bytes();
2327 
2328   if (20 * 1024 * 1024 < num_queued_bytes) {
2329     auto requested_ptzr_track = m_ptzr_to_track_map[requested_ptzr];
2330     if (   !requested_ptzr_track
2331         || (!force && ('a' != requested_ptzr_track->type) && ('v' != requested_ptzr_track->type))
2332         || (!force && (128 * 1024 * 1024 < num_queued_bytes)))
2333       return FILE_STATUS_HOLDING;
2334   }
2335 
2336   try {
2337     auto cluster = m_in_file->read_next_cluster();
2338     if (!cluster)
2339       return finish_file();
2340 
2341     auto cluster_ts = FindChildValue<KaxClusterTimecode>(*cluster);
2342     cluster->InitTimecode(cluster_ts, m_tc_scale);
2343 
2344     size_t bgidx;
2345     for (bgidx = 0; bgidx < cluster->ListSize(); bgidx++) {
2346       EbmlElement *element = (*cluster)[bgidx];
2347 
2348       if (Is<KaxSimpleBlock>(element))
2349         process_simple_block(cluster.get(), static_cast<KaxSimpleBlock *>(element));
2350 
2351       else if (Is<KaxBlockGroup>(element))
2352         process_block_group(cluster.get(), static_cast<KaxBlockGroup *>(element));
2353     }
2354 
2355   } catch (...) {
2356     mxwarn(fmt::format("{0} {1} {2}\n",
2357                        fmt::format(Y("{0}: an unknown exception occurred."), "kax_reader_c::read()"),
2358                        Y("This usually indicates a damaged file structure."), Y("The file will not be processed further.")));
2359     return finish_file();
2360   }
2361 
2362   return FILE_STATUS_MOREDATA;
2363 }
2364 
2365 file_status_e
finish_file()2366 kax_reader_c::finish_file() {
2367   flush_packetizers();
2368 
2369   m_in->setFilePointer(0, seek_end);
2370   m_file_status = FILE_STATUS_DONE;
2371 
2372   return FILE_STATUS_DONE;
2373 }
2374 
2375 void
process_simple_block(KaxCluster * cluster,KaxSimpleBlock * block_simple)2376 kax_reader_c::process_simple_block(KaxCluster *cluster,
2377                                    KaxSimpleBlock *block_simple) {
2378   int64_t block_duration = -1;
2379   int64_t block_bref     = VFT_IFRAME;
2380   int64_t block_fref     = VFT_NOBFRAME;
2381 
2382   block_simple->SetParent(*cluster);
2383   auto block_track     = find_track_by_num(block_simple->TrackNum());
2384   auto block_timestamp = mtx::math::to_signed(block_simple->GlobalTimecode()) - m_global_timestamp_offset;
2385 
2386   if (!block_track) {
2387     if (!m_known_bad_track_numbers[block_simple->TrackNum()])
2388       mxwarn_fn(m_ti.m_fname,
2389                 fmt::format(Y("A block was found at timestamp {0} for track number {1}. However, no headers were found for that track number. "
2390                               "The block will be skipped.\n"), mtx::string::format_timestamp(block_timestamp), block_simple->TrackNum()));
2391     return;
2392   }
2393 
2394   if (0 < block_track->default_duration)
2395     block_duration = block_track->default_duration;
2396   int64_t frame_duration = (block_duration == -1) ? 0 : block_duration;
2397 
2398   if (block_track->ignore_duration_hack) {
2399     frame_duration = 0;
2400     if (0 < block_duration)
2401       block_duration = 0;
2402   }
2403 
2404   auto key_flag         = block_simple->IsKeyframe();
2405   auto discardable_flag = block_simple->IsDiscardable();
2406 
2407   if (!key_flag) {
2408     if (discardable_flag)
2409       block_fref = block_track->previous_timestamp;
2410     else
2411       block_bref = block_track->previous_timestamp;
2412   }
2413 
2414   m_last_timestamp = block_timestamp;
2415   if (0 < block_simple->NumberFrames())
2416     m_in_file->set_last_timestamp(m_last_timestamp + (block_simple->NumberFrames() - 1) * frame_duration);
2417 
2418   if ((-1 != block_track->ptzr) && block_track->passthrough) {
2419     // The handling for passthrough is a bit different. We don't have
2420     // any special cases, e.g. 0 terminating a string for the subs
2421     // and stuff. Just pass everything through as it is.
2422     size_t i;
2423     for (i = 0; block_simple->NumberFrames() > i; ++i) {
2424       DataBuffer &data_buffer = block_simple->GetBuffer(i);
2425       auto data = memory_c::borrow(data_buffer.Buffer(), data_buffer.Size());
2426       block_track->content_decoder.reverse(data, CONTENT_ENCODING_SCOPE_BLOCK);
2427 
2428       packet_cptr packet(new packet_t(data, m_last_timestamp + i * frame_duration, block_duration, block_bref, block_fref));
2429       packet->key_flag         = key_flag;
2430       packet->discardable_flag = discardable_flag;
2431 
2432       ptzr(block_track->ptzr).process(packet);
2433     }
2434 
2435   } else if (-1 != block_track->ptzr) {
2436     size_t i;
2437     for (i = 0; i < block_simple->NumberFrames(); i++) {
2438       DataBuffer &data_buffer = block_simple->GetBuffer(i);
2439       auto data = memory_c::borrow(data_buffer.Buffer(), data_buffer.Size());
2440       block_track->content_decoder.reverse(data, CONTENT_ENCODING_SCOPE_BLOCK);
2441 
2442       auto packet              = std::make_shared<packet_t>(data, m_last_timestamp + i * frame_duration, block_duration, block_bref, block_fref);
2443       packet->key_flag         = key_flag;
2444       packet->discardable_flag = discardable_flag;
2445 
2446       ptzr(block_track->ptzr).process(packet);
2447     }
2448   }
2449 
2450   block_track->previous_timestamp  = m_last_timestamp;
2451   block_track->units_processed    += block_simple->NumberFrames();
2452 }
2453 
2454 void
process_block_group_common(KaxBlockGroup * block_group,packet_t * packet,kax_track_t & block_track)2455 kax_reader_c::process_block_group_common(KaxBlockGroup *block_group,
2456                                          packet_t *packet,
2457                                          kax_track_t &block_track) {
2458   auto codec_state     = FindChild<KaxCodecState>(block_group);
2459   auto discard_padding = FindChild<KaxDiscardPadding>(block_group);
2460   auto blockadd        = FindChild<KaxBlockAdditions>(block_group);
2461 
2462   if (codec_state)
2463     packet->codec_state = memory_c::clone(codec_state->GetBuffer(), codec_state->GetSize());
2464 
2465   if (discard_padding)
2466     packet->discard_padding = timestamp_c::ns(discard_padding->GetValue());
2467 
2468   if (!blockadd)
2469     return;
2470 
2471   for (auto &child : *blockadd) {
2472     if (!(Is<KaxBlockMore>(child)))
2473       continue;
2474 
2475     auto blockmore     = static_cast<KaxBlockMore *>(child);
2476     auto blockadd_data = &GetChild<KaxBlockAdditional>(*blockmore);
2477     auto blockadded    = memory_c::borrow(blockadd_data->GetBuffer(), blockadd_data->GetSize());
2478     block_track.content_decoder.reverse(blockadded, CONTENT_ENCODING_SCOPE_BLOCK);
2479 
2480     packet->data_adds.push_back(blockadded);
2481   }
2482 }
2483 
2484 void
process_block_group(KaxCluster * cluster,KaxBlockGroup * block_group)2485 kax_reader_c::process_block_group(KaxCluster *cluster,
2486                                   KaxBlockGroup *block_group) {
2487   auto block = FindChild<KaxBlock>(block_group);
2488   if (!block)
2489     return;
2490 
2491   block->SetParent(*cluster);
2492   auto block_track     = find_track_by_num(block->TrackNum());
2493   auto block_timestamp = mtx::math::to_signed(block->GlobalTimecode()) - m_global_timestamp_offset;
2494 
2495   if (!block_track) {
2496     if (!m_known_bad_track_numbers[block->TrackNum()])
2497       mxwarn_fn(m_ti.m_fname,
2498                 fmt::format(Y("A block was found at timestamp {0} for track number {1}. However, no headers were found for that track number. "
2499                               "The block will be skipped.\n"), mtx::string::format_timestamp(block_timestamp), block->TrackNum()));
2500     return;
2501   }
2502 
2503   auto duration       = FindChild<KaxBlockDuration>(block_group);
2504   auto block_duration = duration                      ? static_cast<int64_t>(duration->GetValue() * m_tc_scale / block->NumberFrames())
2505                       : block_track->default_duration ? block_track->default_duration
2506                       :                                 int64_t{-1};
2507   auto frame_duration = -1 == block_duration          ? int64_t{0} : block_duration;
2508   m_last_timestamp    = block_timestamp;
2509 
2510   if (0 < block->NumberFrames())
2511     m_in_file->set_last_timestamp(m_last_timestamp + (block->NumberFrames() - 1) * frame_duration);
2512 
2513   if (-1 == block_track->ptzr)
2514     return;
2515 
2516   auto block_bref = int64_t{VFT_IFRAME};
2517   auto block_fref = int64_t{VFT_NOBFRAME};
2518   bool bref_found = false;
2519   bool fref_found = false;
2520   auto ref_block  = FindChild<KaxReferenceBlock>(block_group);
2521 
2522   while (ref_block) {
2523     if (0 >= ref_block->GetValue()) {
2524       block_bref = ref_block->GetValue() * m_tc_scale;
2525       bref_found = true;
2526     } else {
2527       block_fref = ref_block->GetValue() * m_tc_scale;
2528       fref_found = true;
2529     }
2530 
2531     ref_block = FindNextChild(*block_group, *ref_block);
2532   }
2533 
2534   if (block_track->ignore_duration_hack) {
2535     frame_duration = 0;
2536     if (0 < block_duration)
2537       block_duration = 0;
2538   }
2539 
2540   if (block_track->passthrough) {
2541     // The handling for passthrough is a bit different. We don't have
2542     // any special cases, e.g. 0 terminating a string for the subs
2543     // and stuff. Just pass everything through as it is.
2544     if (bref_found)
2545       block_bref += m_last_timestamp;
2546     if (fref_found)
2547       block_fref += m_last_timestamp;
2548 
2549     size_t i;
2550     for (i = 0; i < block->NumberFrames(); i++) {
2551       auto &data_buffer = block->GetBuffer(i);
2552       auto data         = memory_c::borrow(data_buffer.Buffer(), data_buffer.Size());
2553       block_track->content_decoder.reverse(data, CONTENT_ENCODING_SCOPE_BLOCK);
2554 
2555       auto packet                = std::make_shared<packet_t>(data, m_last_timestamp + i * frame_duration, block_duration, block_bref, block_fref);
2556       packet->duration_mandatory = duration;
2557 
2558       process_block_group_common(block_group, packet.get(), *block_track);
2559 
2560       ptzr(block_track->ptzr).process(packet);
2561     }
2562 
2563     return;
2564   }
2565 
2566   if (bref_found)
2567     block_bref += m_last_timestamp;
2568   if (fref_found)
2569     block_fref += m_last_timestamp;
2570 
2571   for (auto block_idx = 0u, num_frames = block->NumberFrames(); block_idx < num_frames; ++block_idx) {
2572     auto &data_buffer = block->GetBuffer(block_idx);
2573     auto data         = memory_c::borrow(data_buffer.Buffer(), data_buffer.Size());
2574     block_track->content_decoder.reverse(data, CONTENT_ENCODING_SCOPE_BLOCK);
2575 
2576     auto packet = std::make_shared<packet_t>(data, m_last_timestamp + block_idx * frame_duration, block_duration, block_bref, block_fref);
2577 
2578     if (duration && !duration->GetValue())
2579       packet->duration_mandatory = true;
2580 
2581     process_block_group_common(block_group, packet.get(), *block_track);
2582 
2583     ptzr(block_track->ptzr).process(packet);
2584   }
2585 
2586   block_track->previous_timestamp  = m_last_timestamp;
2587   block_track->units_processed    += block->NumberFrames();
2588 }
2589 
2590 void
set_headers()2591 kax_reader_c::set_headers() {
2592   generic_reader_c::set_headers();
2593 
2594   for (auto &track : m_tracks)
2595     if ((-1 != track->ptzr) && track->passthrough)
2596       ptzr(track->ptzr).get_track_entry()->EnableLacing(track->lacing_flag);
2597 }
2598 
2599 void
determine_minimum_timestamps()2600 kax_reader_c::determine_minimum_timestamps() {
2601   if (m_tracks.empty())
2602     return;
2603 
2604   m_in->save_pos();
2605   mtx::at_scope_exit_c restore{[this]() { m_in->restore_pos(); }};
2606 
2607   std::unordered_map<uint64_t, kax_track_cptr> tracks_by_number;
2608 
2609   timestamp_c first_timestamp, last_timestamp;
2610   auto probe_time_limit = timestamp_c::s(10);
2611   auto video_time_limit = timestamp_c::s(1);
2612   auto done             = false;
2613 
2614   for (auto &track : m_tracks)
2615     tracks_by_number[track->track_number] = track;
2616 
2617   while (!done) {
2618     try {
2619       auto cluster = m_in_file->read_next_cluster();
2620       if (!cluster)
2621         break;
2622 
2623       auto cluster_ts = FindChildValue<KaxClusterTimecode>(*cluster);
2624       cluster->InitTimecode(cluster_ts, m_tc_scale);
2625 
2626       for (auto const &element : *cluster) {
2627         uint64_t track_number{};
2628 
2629         if (Is<KaxSimpleBlock>(element)) {
2630           auto block = static_cast<KaxSimpleBlock *>(element);
2631           block->SetParent(*cluster);
2632 
2633           last_timestamp = timestamp_c::ns(mtx::math::to_signed(block->GlobalTimecode()));
2634           track_number   = block->TrackNum();
2635 
2636         } else if (Is<KaxBlockGroup>(element)) {
2637           auto block = FindChild<KaxBlock>(static_cast<KaxBlockGroup *>(element));
2638           if (!block)
2639             continue;
2640 
2641           block->SetParent(*cluster);
2642 
2643           last_timestamp = timestamp_c::ns(mtx::math::to_signed(block->GlobalTimecode()));
2644           track_number   = block->TrackNum();
2645 
2646         } else
2647           continue;
2648 
2649         if (!first_timestamp.valid())
2650           first_timestamp = last_timestamp;
2651 
2652         if ((last_timestamp - first_timestamp) >= probe_time_limit) {
2653           done = true;
2654           break;
2655         }
2656 
2657         auto &track = tracks_by_number[track_number];
2658         if (!track)
2659           continue;
2660 
2661         auto &recorded_timestamp = m_minimum_timestamps_by_track_number[track_number];
2662         if (!recorded_timestamp.valid() || (last_timestamp < recorded_timestamp))
2663           recorded_timestamp = last_timestamp;
2664 
2665         if (   (track->type == 'v')
2666             && ((last_timestamp - recorded_timestamp) < video_time_limit))
2667           continue;
2668 
2669         tracks_by_number.erase(track_number);
2670         if (tracks_by_number.empty()) {
2671           done = true;
2672           break;
2673         }
2674       }
2675 
2676     } catch (...) {
2677       break;
2678     }
2679   }
2680 
2681   if (!m_debug_minimum_timestamp)
2682     return;
2683 
2684   auto track_numbers = mtx::keys(m_minimum_timestamps_by_track_number);
2685   std::sort(track_numbers.begin(), track_numbers.end());
2686 
2687   mxdebug("Minimum timestamps by track number:\n");
2688 
2689   for (auto const &track_number : track_numbers)
2690     mxdebug(fmt::format("  {0}: {1}\n", track_number, m_minimum_timestamps_by_track_number[track_number]));
2691 }
2692 
2693 void
determine_global_timestamp_offset_to_apply()2694 kax_reader_c::determine_global_timestamp_offset_to_apply() {
2695   timestamp_c global_minimum_timestamp;
2696 
2697   for (auto const &pair : m_minimum_timestamps_by_track_number) {
2698     if (!pair.second.valid())
2699       continue;
2700 
2701     if (!global_minimum_timestamp.valid() || (pair.second < global_minimum_timestamp))
2702       global_minimum_timestamp = pair.second;
2703   }
2704 
2705   auto use_value = global_minimum_timestamp.valid()
2706                 && ((global_minimum_timestamp < timestamp_c::ns(0)) || m_appending);
2707 
2708   if (use_value)
2709     m_global_timestamp_offset = global_minimum_timestamp.to_ns();
2710 
2711   mxdebug_if(m_debug_minimum_timestamp, fmt::format("Global minimum timestamp: {0}; {1}using it\n", global_minimum_timestamp, use_value ? "" : "not "));
2712 }
2713 
2714 void
identify()2715 kax_reader_c::identify() {
2716   auto info = mtx::id::info_c{};
2717 
2718   if (!m_title.empty())
2719     info.add(mtx::id::title, m_title);
2720   if (0 != m_segment_duration)
2721     info.add(mtx::id::duration, m_segment_duration);
2722 
2723   auto add_uid_info = [&info](memory_cptr const &uid, std::string const &property) {
2724     if (uid)
2725       info.add(property, mtx::string::to_hex(uid, true));
2726   };
2727   add_uid_info(m_segment_uid,          mtx::id::segment_uid);
2728   add_uid_info(m_next_segment_uid,     mtx::id::next_segment_uid);
2729   add_uid_info(m_previous_segment_uid, mtx::id::previous_segment_uid);
2730 
2731   info.set(mtx::id::muxing_application,  m_muxing_app);
2732   info.set(mtx::id::writing_application, m_raw_writing_app);
2733   if (m_muxing_date_epoch) {
2734     auto timestamp = QDateTime::fromSecsSinceEpoch(m_muxing_date_epoch.value(), Qt::UTC);
2735     info.add(mtx::id::date_utc,   mtx::date_time::format_iso_8601(timestamp));
2736     info.add(mtx::id::date_local, mtx::date_time::format_iso_8601(timestamp.toLocalTime()));
2737   }
2738 
2739   id_result_container(info.get());
2740 
2741   for (auto &track : m_tracks) {
2742     if (!track->ok)
2743       continue;
2744 
2745     info = mtx::id::info_c{};
2746 
2747     info.add(mtx::id::number,                 track->track_number);
2748     info.add(mtx::id::uid,                    track->track_uid);
2749     info.add(mtx::id::codec_id,               track->codec_id);
2750     info.set(mtx::id::codec_private_length,   track->private_data ? track->private_data->get_size() : 0u);
2751     info.add(mtx::id::codec_delay,            track->codec_delay.to_ns(0));
2752     info.add(mtx::id::codec_name,             track->codec_name);
2753     info.add(mtx::id::language,               track->language.get_iso639_alpha_3_code());
2754     info.add(mtx::id::language_ietf,          track->language_ietf.format());
2755     info.add(mtx::id::track_name,             track->track_name);
2756     info.add(mtx::id::stereo_mode,            static_cast<int>(track->v_stereo_mode), static_cast<int>(stereo_mode_c::unspecified));
2757     info.add(mtx::id::default_duration,       track->default_duration);
2758     info.set(mtx::id::default_track,          track->default_track ? true : false);
2759     info.set(mtx::id::forced_track,           track->forced_track  ? true : false);
2760     info.set(mtx::id::enabled_track,          track->enabled_track ? true : false);
2761     info.add(mtx::id::flag_hearing_impaired,  track->hearing_impaired_flag);
2762     info.add(mtx::id::flag_visual_impaired,   track->visual_impaired_flag);
2763     info.add(mtx::id::flag_text_descriptions, track->text_descriptions_flag);
2764     info.add(mtx::id::flag_original,          track->original_flag);
2765     info.add(mtx::id::flag_commentary,        track->commentary_flag);
2766 
2767     if (track->private_data && (0 != track->private_data->get_size()))
2768       info.add(mtx::id::codec_private_data, mtx::string::to_hex(track->private_data->get_buffer(), track->private_data->get_size(), true));
2769 
2770     if ((0 != track->v_width) && (0 != track->v_height))
2771       info.add(mtx::id::pixel_dimensions, fmt::format("{0}x{1}", track->v_width, track->v_height));
2772 
2773     if ((0 != track->v_dwidth) && (0 != track->v_dheight))
2774       info.add(mtx::id::display_dimensions, fmt::format("{0}x{1}", track->v_dwidth, track->v_dheight));
2775 
2776     if (track->v_dunit)
2777       info.set(mtx::id::display_unit, *track->v_dunit);
2778 
2779     if ((0 != track->v_pcleft) || (0 != track->v_pctop) || (0 != track->v_pcright) || (0 != track->v_pcbottom))
2780       info.add(mtx::id::cropping, fmt::format("{0},{1},{2},{3}", track->v_pcleft, track->v_pctop, track->v_pcright, track->v_pcbottom));
2781 
2782     if (track->codec.is(codec_c::type_e::V_MPEG4_P10))
2783       info.add(mtx::id::packetizer, track->ms_compat ? mtx::id::mpeg4_p10_es_video : mtx::id::mpeg4_p10_video);
2784     else if (track->codec.is(codec_c::type_e::V_MPEGH_P2))
2785       info.add(mtx::id::packetizer, track->ms_compat ? mtx::id::mpegh_p2_es_video  : mtx::id::mpegh_p2_video);
2786 
2787     if ('a' == track->type) {
2788       info.add(mtx::id::audio_sampling_frequency, static_cast<int64_t>(track->a_sfreq));
2789       info.add(mtx::id::audio_channels,           track->a_channels);
2790       info.add(mtx::id::audio_bits_per_sample,    track->a_bps);
2791 
2792     } else if ('s' == track->type) {
2793       if (track->codec.is(codec_c::type_e::S_SRT) || track->codec.is(codec_c::type_e::S_SSA_ASS) || track->codec.is(codec_c::type_e::S_KATE)) {
2794         info.add(mtx::id::text_subtitles, true);
2795         info.add(mtx::id::encoding, "UTF-8");
2796       }
2797     }
2798 
2799     if (track->content_decoder.has_encodings())
2800       info.add(mtx::id::content_encoding_algorithms, track->content_decoder.descriptive_algorithm_list());
2801 
2802     std::string codec_info;
2803     if (track->codec)
2804       codec_info = track->codec.get_name();
2805 
2806     else if (track->ms_compat) {
2807       if (track->type == 'v') {
2808         // auto fourcc_str = fourcc_c{track->v_fourcc}.description();
2809         // codec_info            = track->codec.get_name(fourcc_str);
2810 
2811         codec_info = fourcc_c{track->v_fourcc}.description();
2812 
2813       } else
2814         codec_info = fmt::format(Y("unknown, format tag 0x{0:04x}"), track->a_formattag);
2815 
2816     } else
2817       codec_info = track->codec_id;
2818 
2819     if (track->tags)
2820       add_track_tags_to_identification(*track->tags, info);
2821 
2822     auto &minimum_timestamp = m_minimum_timestamps_by_track_number[track->track_number];
2823     if (minimum_timestamp.valid())
2824       info.set(mtx::id::minimum_timestamp, minimum_timestamp.to_ns());
2825 
2826     id_result_track(track->tnum,
2827                       track->type == 'v' ? ID_RESULT_TRACK_VIDEO
2828                     : track->type == 'a' ? ID_RESULT_TRACK_AUDIO
2829                     : track->type == 'b' ? ID_RESULT_TRACK_BUTTONS
2830                     : track->type == 's' ? ID_RESULT_TRACK_SUBTITLES
2831                     :                      Y("unknown"),
2832                     codec_info, info.get());
2833   }
2834 
2835   for (auto &attachment : g_attachments)
2836     id_result_attachment(attachment->ui_id, attachment->mime_type, attachment->data->get_size(), attachment->name, attachment->description, attachment->id);
2837 
2838   if (m_chapters)
2839     id_result_chapters(mtx::chapters::count_atoms(*m_chapters));
2840 
2841   if (m_tags)
2842     id_result_tags(ID_RESULT_GLOBAL_TAGS_ID, mtx::tags::count_simple(*m_tags));
2843 
2844   for (auto &track : m_tracks)
2845     if (track->ok && track->tags)
2846       id_result_tags(track->tnum, mtx::tags::count_simple(*track->tags));
2847 }
2848 
2849 void
add_available_track_ids()2850 kax_reader_c::add_available_track_ids() {
2851   for (auto &track : m_tracks)
2852     add_available_track_id(track->tnum);
2853 
2854   if (m_chapters)
2855     add_available_track_id(track_info_c::chapter_track_id);
2856 }
2857 
2858 void
set_track_packetizer(kax_track_t * t,generic_packetizer_c * packetizer)2859 kax_reader_c::set_track_packetizer(kax_track_t *t,
2860                                    generic_packetizer_c *packetizer) {
2861   t->ptzr     = add_packetizer(packetizer);
2862   t->ptzr_ptr = packetizer;
2863 }
2864 
2865 void
handle_vorbis_comments_cover_art(mtx::tags::converted_vorbis_comments_t const & converted)2866 kax_reader_c::handle_vorbis_comments_cover_art(mtx::tags::converted_vorbis_comments_t const &converted) {
2867   for (auto const &picture : converted.m_pictures) {
2868     picture->ui_id        = ++m_attachment_id;
2869     picture->source_file  = m_ti.m_fname;
2870     auto attach_mode      = attachment_requested(picture->ui_id);
2871     picture->to_all_files = ATTACH_MODE_TO_ALL_FILES == attach_mode;
2872 
2873     if (ATTACH_MODE_SKIP != attach_mode)
2874       add_attachment(picture);
2875   }
2876 }
2877 
2878 void
handle_vorbis_comments_tags(mtx::tags::converted_vorbis_comments_t const & converted,kax_track_t & t)2879 kax_reader_c::handle_vorbis_comments_tags(mtx::tags::converted_vorbis_comments_t const &converted,
2880                                           kax_track_t &t) {
2881   if (!converted.m_track_tags && !converted.m_album_tags)
2882     return;
2883 
2884   t.tags = mtx::tags::merge(t.tags, mtx::tags::merge(converted.m_track_tags, converted.m_album_tags));
2885 }
2886 
2887 void
handle_vorbis_comments(kax_track_t & t)2888 kax_reader_c::handle_vorbis_comments(kax_track_t &t) {
2889   auto comments = mtx::tags::parse_vorbis_comments_from_packet(*t.headers[1]);
2890   if (!comments.valid())
2891     return;
2892 
2893   auto converted = mtx::tags::from_vorbis_comments(comments);
2894 
2895   handle_vorbis_comments_cover_art(converted);
2896   handle_vorbis_comments_tags(converted, t);
2897 
2898   comments.m_comments.clear();
2899   t.headers[1] = mtx::tags::assemble_vorbis_comments_into_packet(comments);
2900 }
2901