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