Tag Parser 12.5.1
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
Loading...
Searching...
No Matches
overallmkv.cpp
Go to the documentation of this file.
1#include <c++utilities/chrono/format.h>
2
3#include "./overall.h"
4
5#include "../abstracttrack.h"
7#include "../mp4/mp4ids.h"
9
10#include <c++utilities/chrono/timespan.h>
11#include <c++utilities/conversion/binaryconversion.h>
12#include <c++utilities/conversion/stringconversion.h>
13#include <c++utilities/io/misc.h>
14
15#include <cstring>
16#include <fstream>
17
18using namespace CppUtilities;
19
33
37void OverallTests::checkMkvTestfile1()
38{
39 CPPUNIT_ASSERT_EQUAL(ContainerFormat::Matroska, m_fileInfo.containerFormat());
40 CPPUNIT_ASSERT_EQUAL(TimeSpan::fromMinutes(1.0) + TimeSpan::fromSeconds(27.0) + TimeSpan::fromMilliseconds(336.0), m_fileInfo.duration());
41 const auto tracks = m_fileInfo.tracks();
42 CPPUNIT_ASSERT_EQUAL(2_st, tracks.size());
43 for (const auto &track : tracks) {
44 switch (track->id()) {
45 case 2422994868:
46 CPPUNIT_ASSERT_EQUAL(MediaType::Video, track->mediaType());
47 CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::MicrosoftMpeg4, track->format().general);
48 CPPUNIT_ASSERT(track->isEnabled());
49 CPPUNIT_ASSERT(!track->isForced());
50 CPPUNIT_ASSERT(track->isDefault());
51 break;
52 case 3653291187:
53 CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
54 CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Mpeg1Audio, track->format().general);
55 CPPUNIT_ASSERT_EQUAL(48000u, track->samplingFrequency());
56 CPPUNIT_ASSERT(track->isEnabled());
57 CPPUNIT_ASSERT(!track->isForced());
58 CPPUNIT_ASSERT(track->isDefault());
59 break;
60 default:
61 CPPUNIT_FAIL("unknown track ID");
62 }
63 }
64 const auto tags = m_fileInfo.tags();
65 switch (m_tagStatus) {
67 CPPUNIT_ASSERT_EQUAL(1_st, tags.size());
68 CPPUNIT_ASSERT_EQUAL("Big Buck Bunny - test 1"s, tags.front()->value(KnownField::Title).toString());
69 CPPUNIT_ASSERT_EQUAL(TagValue(), tags.front()->value(KnownField::Artist));
70 CPPUNIT_ASSERT_EQUAL(
71 "Matroska Validation File1, basic MPEG4.2 and MP3 with only SimpleBlock"s, tags.front()->value(KnownField::Comment).toString());
72 CPPUNIT_ASSERT_EQUAL("2010"s, tags.front()->value(KnownField::ReleaseDate).toString());
73 break;
75 checkMkvTestMetaData();
76 break;
78 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
79 }
80 CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
81}
82
86void OverallTests::checkMkvTestfile2()
87{
88 CPPUNIT_ASSERT_EQUAL(ContainerFormat::Matroska, m_fileInfo.containerFormat());
89 CPPUNIT_ASSERT_EQUAL(TimeSpan::fromSeconds(47.0) + TimeSpan::fromMilliseconds(509.0), m_fileInfo.duration());
90 const auto tracks = m_fileInfo.tracks();
91 CPPUNIT_ASSERT_EQUAL(2_st, tracks.size());
92 for (const auto &track : tracks) {
93 switch (track->id()) {
94 case 1863976627:
95 CPPUNIT_ASSERT_EQUAL(MediaType::Video, track->mediaType());
96 CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Avc, track->format().general);
97 CPPUNIT_ASSERT_EQUAL(Size(1354, 576), track->displaySize());
98 CPPUNIT_ASSERT(track->isEnabled());
99 CPPUNIT_ASSERT(!track->isForced());
100 CPPUNIT_ASSERT(track->isDefault());
101 break;
102 case 3134325680:
103 CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
104 CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Aac, track->format().general);
105 CPPUNIT_ASSERT_EQUAL(48000u, track->samplingFrequency());
106 CPPUNIT_ASSERT(track->isEnabled());
107 CPPUNIT_ASSERT(!track->isForced());
108 CPPUNIT_ASSERT(track->isDefault());
109 break;
110 default:
111 CPPUNIT_FAIL("unknown track ID");
112 }
113 }
114 const auto tags = m_fileInfo.tags();
115 switch (m_tagStatus) {
117 CPPUNIT_ASSERT_EQUAL(1_st, tags.size());
118 CPPUNIT_ASSERT_EQUAL("Elephant Dream - test 2"s, tags.front()->value(KnownField::Title).toString());
119 CPPUNIT_ASSERT_EQUAL(TagValue(), tags.front()->value(KnownField::Artist));
120 CPPUNIT_ASSERT_EQUAL("Matroska Validation File 2, 100,000 timecode scale, odd aspect ratio, and CRC-32. Codecs are AVC and AAC"s,
121 tags.front()->value(KnownField::Comment).toString());
122 break;
124 checkMkvTestMetaData();
125 break;
127 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
128 }
129 CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
130}
131
135void OverallTests::checkMkvTestfile3()
136{
137 CPPUNIT_ASSERT_EQUAL(ContainerFormat::Matroska, m_fileInfo.containerFormat());
138 CPPUNIT_ASSERT_EQUAL(TimeSpan::fromSeconds(49.0) + TimeSpan::fromMilliseconds(64.0), m_fileInfo.duration());
139 const auto tracks = m_fileInfo.tracks();
140 CPPUNIT_ASSERT_EQUAL(2_st, tracks.size());
141 for (const auto &track : tracks) {
142 switch (track->id()) {
143 case 3927961528:
144 CPPUNIT_ASSERT_EQUAL(MediaType::Video, track->mediaType());
145 CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Avc, track->format().general);
146 CPPUNIT_ASSERT_EQUAL(Size(1024, 576), track->displaySize());
147 CPPUNIT_ASSERT(track->isEnabled());
148 CPPUNIT_ASSERT(!track->isForced());
149 CPPUNIT_ASSERT(track->isDefault());
150 break;
151 case 3391885737:
152 CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
153 CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Mpeg1Audio, track->format().general);
154 CPPUNIT_ASSERT_EQUAL(48000u, track->samplingFrequency());
155 CPPUNIT_ASSERT(track->isEnabled());
156 CPPUNIT_ASSERT(!track->isForced());
157 CPPUNIT_ASSERT(track->isDefault());
158 break;
159 default:
160 CPPUNIT_FAIL("unknown track ID");
161 }
162 }
163 const auto tags = m_fileInfo.tags();
164 switch (m_tagStatus) {
166 CPPUNIT_ASSERT_EQUAL(1_st, tags.size());
167 CPPUNIT_ASSERT_EQUAL("Elephant Dream - test 3"s, tags.front()->value(KnownField::Title).toString());
168 CPPUNIT_ASSERT_EQUAL(TagValue(), tags.front()->value(KnownField::Artist));
169 CPPUNIT_ASSERT_EQUAL("Matroska Validation File 3, header stripping on the video track and no SimpleBlock"s,
170 tags.front()->value(KnownField::Comment).toString());
171 break;
173 checkMkvTestMetaData();
174 break;
176 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
177 }
178 CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
179}
180
185void OverallTests::checkMkvTestfile4()
186{
187 CPPUNIT_ASSERT_EQUAL(ContainerFormat::Matroska, m_fileInfo.containerFormat());
188 CPPUNIT_ASSERT_EQUAL(TimeSpan(), m_fileInfo.duration());
189 // this file is messed up, it should contain tags but it doesn't
190 const auto tracks = m_fileInfo.tracks();
191 CPPUNIT_ASSERT_EQUAL(2_st, tracks.size());
192 for (const auto &track : tracks) {
193 switch (track->id()) {
194 case 1368622492:
195 CPPUNIT_ASSERT_EQUAL(MediaType::Video, track->mediaType());
196 CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Theora, track->format().general);
197 CPPUNIT_ASSERT_EQUAL(Size(1280, 720), track->displaySize());
198 break;
199 case 3171450505:
200 CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
201 CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Vorbis, track->format().general);
202 CPPUNIT_ASSERT_EQUAL(48000u, track->samplingFrequency());
203 CPPUNIT_ASSERT_EQUAL(static_cast<std::uint16_t>(2u), track->channelCount());
204 switch (m_tagStatus) {
207 CPPUNIT_ASSERT_EQUAL(Locale("und"sv, LocaleFormat::ISO_639_2_B), track->locale());
208 CPPUNIT_ASSERT_EQUAL(string(), track->name());
209 CPPUNIT_ASSERT(track->isEnabled());
210 CPPUNIT_ASSERT(!track->isForced());
211 CPPUNIT_ASSERT(track->isDefault());
212 break;
214 CPPUNIT_ASSERT_EQUAL(Locale("ger"sv, LocaleFormat::ISO_639_2_B), track->locale());
215 CPPUNIT_ASSERT_EQUAL("the name"s, track->name());
216 CPPUNIT_ASSERT(track->isEnabled());
217 CPPUNIT_ASSERT(track->isForced());
218 CPPUNIT_ASSERT(!track->isDefault());
219 break;
220 }
221 break;
222 default:
223 CPPUNIT_FAIL("unknown track ID");
224 }
225 }
226 const auto tags = m_fileInfo.tags();
227 switch (m_tagStatus) {
230 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
231 break;
233 checkMkvTestMetaData();
234 break;
235 }
236
237 // tolerate critical notifications here because live stream feature used by the file is not supported in v6 yet
238 CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Critical);
239}
240
244void OverallTests::checkMkvTestfile5()
245{
246 CPPUNIT_ASSERT_EQUAL(ContainerFormat::Matroska, m_fileInfo.containerFormat());
247 CPPUNIT_ASSERT_EQUAL(TimeSpan::fromSeconds(46.0) + TimeSpan::fromMilliseconds(665.0), m_fileInfo.duration());
248 const auto tracks = m_fileInfo.tracks();
249 CPPUNIT_ASSERT_EQUAL(11_st, tracks.size());
250 for (const auto &track : tracks) {
251 switch (track->id()) {
252 case 1258329745:
253 CPPUNIT_ASSERT_EQUAL(MediaType::Video, track->mediaType());
254 CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Avc, track->format().general);
255 CPPUNIT_ASSERT_EQUAL(Size(1024, 576), track->displaySize());
256 CPPUNIT_ASSERT_EQUAL(true, track->isDefault());
257 CPPUNIT_ASSERT_EQUAL(true, track->isEnabled());
258 CPPUNIT_ASSERT_EQUAL(false, track->isForced());
259 break;
260 case 3452711582:
261 CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
262 CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Aac, track->format().general);
263 CPPUNIT_ASSERT_EQUAL(48000u, track->samplingFrequency());
264 CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(Mpeg4ChannelConfigs::FrontLeftFrontRight), track->channelConfig());
265 CPPUNIT_ASSERT_EQUAL(true, track->isDefault());
266 CPPUNIT_ASSERT_EQUAL(true, track->isEnabled());
267 CPPUNIT_ASSERT_EQUAL(false, track->isForced());
268 break;
269 case 3554194305:
270 CPPUNIT_ASSERT_EQUAL(MediaType::Text, track->mediaType());
271 CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::TextSubtitle, track->format().general);
272 CPPUNIT_ASSERT_EQUAL(Locale("ger"sv, LocaleFormat::ISO_639_2_B), track->locale());
273 break;
274 default:;
275 }
276 }
277 const auto tags = m_fileInfo.tags();
278 switch (m_tagStatus) {
280 CPPUNIT_ASSERT_EQUAL(1_st, tags.size());
281 CPPUNIT_ASSERT_EQUAL("Big Buck Bunny - test 8"s, tags.front()->value(KnownField::Title).toString());
282 CPPUNIT_ASSERT_EQUAL(TagValue(), tags.front()->value(KnownField::Artist));
283 CPPUNIT_ASSERT_EQUAL("Matroska Validation File 8, secondary audio commentary track, misc subtitle tracks"s,
284 tags.front()->value(KnownField::Comment).toString());
285 break;
287 checkMkvTestMetaData();
288 break;
290 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
291 }
292 CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
293}
294
298void OverallTests::checkMkvTestfile6()
299{
300 CPPUNIT_ASSERT_EQUAL(ContainerFormat::Matroska, m_fileInfo.containerFormat());
301 CPPUNIT_ASSERT_EQUAL(TimeSpan::fromMinutes(1.0) + TimeSpan::fromSeconds(27.0) + TimeSpan::fromMilliseconds(336.0), m_fileInfo.duration());
302 const auto tracks = m_fileInfo.tracks();
303 CPPUNIT_ASSERT_EQUAL(2_st, tracks.size());
304 for (const auto &track : tracks) {
305 switch (track->id()) {
306 case 2422994868:
307 CPPUNIT_ASSERT_EQUAL(MediaType::Video, track->mediaType());
308 CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::MicrosoftMpeg4, track->format().general);
309 CPPUNIT_ASSERT_EQUAL(Size(854, 480), track->displaySize());
310 CPPUNIT_ASSERT_EQUAL(false, track->isDefault());
311 CPPUNIT_ASSERT_EQUAL(true, track->isEnabled());
312 CPPUNIT_ASSERT_EQUAL(false, track->isForced());
313 break;
314 case 3653291187:
315 CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
316 CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Mpeg1Audio, track->format().general);
317 CPPUNIT_ASSERT_EQUAL(48000u, track->samplingFrequency());
318 CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(MpegChannelMode::Stereo), track->channelConfig());
319 CPPUNIT_ASSERT_EQUAL(false, track->isDefault());
320 CPPUNIT_ASSERT_EQUAL(true, track->isEnabled());
321 CPPUNIT_ASSERT_EQUAL(false, track->isForced());
322 break;
323 default:
324 CPPUNIT_FAIL("unknown track ID");
325 }
326 }
327 const auto tags = m_fileInfo.tags();
328 switch (m_tagStatus) {
330 CPPUNIT_ASSERT_EQUAL(1_st, tags.size());
331 CPPUNIT_ASSERT_EQUAL("Big Buck Bunny - test 6"s, tags.front()->value(KnownField::Title).toString());
332 CPPUNIT_ASSERT_EQUAL(TagValue(), tags.front()->value(KnownField::Artist));
333 CPPUNIT_ASSERT_EQUAL("Matroska Validation File 6, random length to code the size of Clusters and Blocks, no Cues for seeking"s,
334 tags.front()->value(KnownField::Comment).toString());
335 break;
337 checkMkvTestMetaData();
338 break;
340 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
341 }
342 CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
343}
344
348void OverallTests::checkMkvTestfile7()
349{
350 CPPUNIT_ASSERT_EQUAL(ContainerFormat::Matroska, m_fileInfo.containerFormat());
351 CPPUNIT_ASSERT_EQUAL(TimeSpan::fromSeconds(37.0) + TimeSpan::fromMilliseconds(43.0), m_fileInfo.duration());
352 const auto tracks = m_fileInfo.tracks();
353 CPPUNIT_ASSERT_EQUAL(2_st, tracks.size());
354 for (const auto &track : tracks) {
355 switch (track->id()) {
356 case 568001708:
357 CPPUNIT_ASSERT_EQUAL(MediaType::Video, track->mediaType());
358 CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Avc, track->format().general);
359 CPPUNIT_ASSERT_EQUAL(Size(1024, 576), track->displaySize());
360 CPPUNIT_ASSERT_EQUAL("YUV 4:2:0"s, string(track->chromaFormat()));
361 CPPUNIT_ASSERT_EQUAL(false, track->isDefault());
362 CPPUNIT_ASSERT_EQUAL(true, track->isEnabled());
363 CPPUNIT_ASSERT_EQUAL(false, track->isForced());
364 break;
365 case 2088735154:
366 CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
367 CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Aac, track->format().general);
368 CPPUNIT_ASSERT_EQUAL(48000u, track->samplingFrequency());
369 CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(Mpeg4ChannelConfigs::FrontLeftFrontRight), track->channelConfig());
370 CPPUNIT_ASSERT_EQUAL(false, track->isDefault());
371 CPPUNIT_ASSERT_EQUAL(true, track->isEnabled());
372 CPPUNIT_ASSERT_EQUAL(false, track->isForced());
373 break;
374 default:
375 CPPUNIT_FAIL("unknown track ID");
376 }
377 }
378 const auto tags = m_fileInfo.tags();
379 switch (m_tagStatus) {
381 CPPUNIT_ASSERT_EQUAL(1_st, tags.size());
382 CPPUNIT_ASSERT_EQUAL("Big Buck Bunny - test 7"s, tags.front()->value(KnownField::Title).toString());
383 CPPUNIT_ASSERT_EQUAL(TagValue(), tags.front()->value(KnownField::Artist));
384 CPPUNIT_ASSERT_EQUAL( // note: Typo "beggining" is present in `test7.mkv` from https://matroska.org/downloads/test_suite.html, do not fix it.
385 "Matroska Validation File 7, junk elements are present at the beggining or end of clusters, the parser should skip it. There is also a damaged element at 451418"s,
386 tags.front()->value(KnownField::Comment).toString());
387 break;
389 checkMkvTestMetaData();
390 break;
392 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
393 }
394
395 for (const auto &msg : m_diag) {
396 if (msg.level() != DiagLevel::Warning) {
397 continue;
398 }
399 CPPUNIT_ASSERT(startsWith(msg.context(), "parsing header of EBML element 0xEA \"cue codec state\" at"));
400 CPPUNIT_ASSERT_EQUAL("Data of EBML element seems to be truncated; unable to parse siblings of that element."s, msg.message());
401 }
402 CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Warning);
403}
404
408void OverallTests::checkMkvTestfile8()
409{
410 CPPUNIT_ASSERT_EQUAL(ContainerFormat::Matroska, m_fileInfo.containerFormat());
411 CPPUNIT_ASSERT_EQUAL(TimeSpan::fromSeconds(47.0) + TimeSpan::fromMilliseconds(341.0), m_fileInfo.duration());
412 const auto tracks = m_fileInfo.tracks();
413 CPPUNIT_ASSERT_EQUAL(2_st, tracks.size());
414 for (const auto &track : tracks) {
415 switch (track->id()) {
416 case 568001708:
417 CPPUNIT_ASSERT_EQUAL(MediaType::Video, track->mediaType());
418 CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Avc, track->format().general);
419 CPPUNIT_ASSERT_EQUAL(Size(1024, 576), track->displaySize());
420 CPPUNIT_ASSERT_EQUAL("YUV 4:2:0"s, string(track->chromaFormat()));
421 CPPUNIT_ASSERT_EQUAL(false, track->isDefault());
422 CPPUNIT_ASSERT_EQUAL(true, track->isEnabled());
423 CPPUNIT_ASSERT_EQUAL(false, track->isForced());
424 break;
425 case 2088735154:
426 CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
427 CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Aac, track->format().general);
428 CPPUNIT_ASSERT_EQUAL(48000u, track->samplingFrequency());
429 CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(Mpeg4ChannelConfigs::FrontLeftFrontRight), track->channelConfig());
430 CPPUNIT_ASSERT_EQUAL(false, track->isDefault());
431 CPPUNIT_ASSERT_EQUAL(true, track->isEnabled());
432 CPPUNIT_ASSERT_EQUAL(false, track->isForced());
433 break;
434 default:
435 CPPUNIT_FAIL("unknown track ID");
436 }
437 }
438 const auto tags = m_fileInfo.tags();
439 switch (m_tagStatus) {
441 CPPUNIT_ASSERT_EQUAL(1_st, tags.size());
442 CPPUNIT_ASSERT_EQUAL("Big Buck Bunny - test 8"s, tags.front()->value(KnownField::Title).toString());
443 CPPUNIT_ASSERT_EQUAL(TagValue(), tags.front()->value(KnownField::Artist));
444 CPPUNIT_ASSERT_EQUAL(
445 "Matroska Validation File 8, audio missing between timecodes 6.019s and 6.360s"s, tags.front()->value(KnownField::Comment).toString());
446 break;
448 checkMkvTestMetaData();
449 break;
451 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
452 }
453 CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
454}
455
459void OverallTests::checkMkvTestfileHandbrakeChapters()
460{
461 CPPUNIT_ASSERT_EQUAL(ContainerFormat::Matroska, m_fileInfo.containerFormat());
462 CPPUNIT_ASSERT_EQUAL(TimeSpan::fromSeconds(27.0) + TimeSpan::fromMilliseconds(569.0), m_fileInfo.duration());
463 const auto tracks = m_fileInfo.tracks();
464 CPPUNIT_ASSERT_EQUAL(2_st, tracks.size());
465 for (const auto &track : tracks) {
466 switch (track->id()) {
467 case 1:
468 CPPUNIT_ASSERT_EQUAL(MediaType::Video, track->mediaType());
469 CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Avc, track->format().general);
470 CPPUNIT_ASSERT_EQUAL(4.0, track->version());
471 CPPUNIT_ASSERT_EQUAL(Size(1280, 544), track->pixelSize());
472 CPPUNIT_ASSERT_EQUAL(Size(1280, 544), track->displaySize());
473 CPPUNIT_ASSERT_EQUAL(23u, track->fps());
474 CPPUNIT_ASSERT_EQUAL(true, track->isDefault());
475 CPPUNIT_ASSERT_EQUAL(true, track->isEnabled());
476 CPPUNIT_ASSERT_EQUAL(false, track->isForced());
477 break;
478 case 2:
479 CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
480 CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Aac, track->format().general);
481 CPPUNIT_ASSERT_EQUAL(44100u, track->samplingFrequency());
482 CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(Mpeg4ChannelConfigs::FrontLeftFrontRight), track->channelConfig());
483 CPPUNIT_ASSERT_EQUAL(true, track->isDefault());
484 CPPUNIT_ASSERT_EQUAL(true, track->isEnabled());
485 CPPUNIT_ASSERT_EQUAL(false, track->isForced());
486 break;
487 default:
488 CPPUNIT_FAIL(argsToString("unknown track ID ", track->id()));
489 }
490 }
491 const auto chapters = m_fileInfo.chapters();
492 CPPUNIT_ASSERT_EQUAL(2_st, chapters.size());
493 for (const auto &chapter : chapters) {
494 switch (chapter->id()) {
495 case 1:
496 CPPUNIT_ASSERT_EQUAL("Kapitel 01"s, static_cast<const string &>(chapter->names().at(0)));
497 CPPUNIT_ASSERT_EQUAL(static_cast<std::int64_t>(0), chapter->startTime().totalTicks());
498 CPPUNIT_ASSERT_EQUAL(15, chapter->endTime().seconds());
499 break;
500 case 2:
501 CPPUNIT_ASSERT_EQUAL("Kapitel 02"s, static_cast<const string &>(chapter->names().at(0)));
502 CPPUNIT_ASSERT_EQUAL(15, chapter->startTime().seconds());
503 CPPUNIT_ASSERT_EQUAL(27, chapter->endTime().seconds());
504 break;
505 default:
506 CPPUNIT_FAIL(argsToString("unknown chapter ID ", chapter->id()));
507 }
508 }
509 const auto tags = m_fileInfo.tags();
510 switch (m_tagStatus) {
512 CPPUNIT_ASSERT_EQUAL(2_st, tags.size());
513 CPPUNIT_ASSERT(tags[0]->target().isEmpty());
514 CPPUNIT_ASSERT_EQUAL(""s, static_cast<MatroskaTag *>(tags[0])->value("CREATION_TIME").toString());
515 CPPUNIT_ASSERT_EQUAL("Lavf55.12.0"s, tags[0]->value(KnownField::Encoder).toString());
516 CPPUNIT_ASSERT_EQUAL(static_cast<TagTarget::IdType>(2), tags[1]->target().tracks().at(0));
517 CPPUNIT_ASSERT_EQUAL("eng"s, tags[1]->value(KnownField::Language).toString());
518 break;
520 checkMkvTestMetaData();
521 break;
523 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
524 }
525 CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
526}
527
531void OverallTests::checkMkvTestfileNestedTags()
532{
533 CPPUNIT_ASSERT_EQUAL(ContainerFormat::Matroska, m_fileInfo.containerFormat());
534 const auto tags = m_fileInfo.tags();
535 bool generalTagFound = false;
536 switch (m_tagStatus) {
539 CPPUNIT_ASSERT_EQUAL(5_st, tags.size());
540 for (const Tag *tag : tags) {
541 CPPUNIT_ASSERT(tag->type() == TagType::MatroskaTag);
542 const auto *mkvTag = static_cast<const MatroskaTag *>(tag);
543 const auto &target = mkvTag->target();
544 if (target.level() == 50 && target.tracks().empty()) {
545 generalTagFound = true;
546 CPPUNIT_ASSERT_EQUAL("Vanilla Sky"s, tag->value(KnownField::Title).toString());
547 const auto &fields = mkvTag->fields();
548 const auto &artistField = fields.find(mkvTag->fieldId(KnownField::Artist));
549 CPPUNIT_ASSERT(artistField != fields.end());
550 CPPUNIT_ASSERT_EQUAL("Test artist"s, artistField->second.value().toString());
551 const auto &nestedFields = artistField->second.nestedFields();
552 CPPUNIT_ASSERT_EQUAL(1_st, nestedFields.size());
553 CPPUNIT_ASSERT_EQUAL("ADDRESS"s, nestedFields[0].idToString());
554 CPPUNIT_ASSERT_EQUAL("Test address"s, nestedFields[0].value().toString());
555 }
556 }
557 CPPUNIT_ASSERT(generalTagFound);
558 break;
560 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
561 }
562
563 // the file contains in fact the unknown element [44][B4]
564 // TODO: find out what this element is about (its data is only the single byte 0x01)
565 for (const auto &msg : m_diag) {
566 if (msg.level() != DiagLevel::Warning) {
567 continue;
568 }
569 CPPUNIT_ASSERT(startsWith(msg.message(), "\"SimpleTag\"-element contains unknown element 0x44B4 at"));
570 }
571 CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Warning);
572}
573
577void OverallTests::checkMkvTestMetaData()
578{
579 // check tags
580 const auto tags = m_fileInfo.tags();
581 const auto tracks = m_fileInfo.tracks();
582 CPPUNIT_ASSERT_EQUAL(2_st, tags.size());
583 CPPUNIT_ASSERT_EQUAL(m_testTitle.toString(), tags.front()->value(KnownField::Title).toString());
584 CPPUNIT_ASSERT(tags.front()->value(KnownField::Artist).isEmpty());
585 CPPUNIT_ASSERT_EQUAL(m_testComment.toString(), tags.front()->value(KnownField::Comment).toString());
586 CPPUNIT_ASSERT_EQUAL(static_cast<std::uint64_t>(30), tags[1]->target().level());
587 CPPUNIT_ASSERT_EQUAL(tracks.at(0)->id(), tags[1]->target().tracks().at(0));
588 CPPUNIT_ASSERT_EQUAL(m_testAlbum.toString(), tags[1]->value(KnownField::Album).toString());
589 CPPUNIT_ASSERT_EQUAL(m_testPartNumber.toInteger(), tags[1]->value(KnownField::PartNumber).toInteger());
590 CPPUNIT_ASSERT_EQUAL(m_testTotalParts.toInteger(), tags[1]->value(KnownField::TotalParts).toInteger());
591
592 // check attachments
593 const auto attachments = m_fileInfo.attachments();
594 CPPUNIT_ASSERT_EQUAL(1_st, attachments.size());
595 CPPUNIT_ASSERT_EQUAL("image/png"s, attachments[0]->mimeType());
596 CPPUNIT_ASSERT_EQUAL("cover.jpg"s, attachments[0]->name());
597 const StreamDataBlock *attachmentData = attachments[0]->data();
598 CPPUNIT_ASSERT(attachmentData != nullptr);
599 if (m_testCover.empty()) {
600 m_testCover = readFile(testFilePath("matroska_wave1/logo3_256x256.png"), 20000);
601 }
602 CPPUNIT_ASSERT_EQUAL(m_testCover.size(), static_cast<size_t>(attachmentData->size()));
603 istream &attachmentSteam = attachmentData->stream();
604 attachmentSteam.seekg(static_cast<std::streamoff>(attachmentData->startOffset()), std::ios_base::beg);
605 for (char expectedChar : m_testCover) {
606 CPPUNIT_ASSERT_EQUAL(expectedChar, static_cast<char>(attachmentSteam.get()));
607 }
608}
609
613void OverallTests::checkMkvConstraints()
614{
615 using namespace MkvTestFlags;
616
617 CPPUNIT_ASSERT(m_fileInfo.container());
618 if (m_mode & PaddingConstraints) {
619 if (m_mode & ForceRewring) {
620 CPPUNIT_ASSERT_EQUAL(static_cast<std::uint64_t>(4096), m_fileInfo.paddingSize());
621 } else {
622 CPPUNIT_ASSERT(m_fileInfo.paddingSize() >= 1024);
623 CPPUNIT_ASSERT(m_fileInfo.paddingSize() <= (4096 + 1024));
624 }
625 if (!(m_mode & RemoveTag) && (m_expectedTagPos != ElementPosition::Keep) && ((m_mode & ForceRewring) || (m_mode & ForceTagPos))) {
626 CPPUNIT_ASSERT_EQUAL(m_expectedTagPos, m_fileInfo.container()->determineTagPosition(m_diag));
627 }
628 if ((m_expectedIndexPos != ElementPosition::Keep) && ((m_mode & ForceRewring) || (m_mode & ForceIndexPos))) {
629 CPPUNIT_ASSERT_EQUAL(m_expectedIndexPos, m_fileInfo.container()->determineIndexPosition(m_diag));
630 }
631 }
632}
633
637void OverallTests::setMkvTestMetaData()
638{
639 CPPUNIT_ASSERT_EQUAL(ContainerFormat::Matroska, m_fileInfo.containerFormat());
640 auto *container = static_cast<MatroskaContainer *>(m_fileInfo.container());
641
642 // change the present tag
643 const string fileName(m_fileInfo.fileName());
644 if (fileName == "test4.mkv") {
645 // test4.mkv has no tag, so one must be created first
646 container->createTag(TagTarget(50));
647 // also change language, name, forced and default of track "3171450505" to German
648 MatroskaTrack *track = container->trackById(3171450505);
649 CPPUNIT_ASSERT(track);
650 track->setLocale(Locale("ger"sv, LocaleFormat::ISO_639_2_B));
651 track->setName("the name");
652 track->setDefault(false);
653 track->setEnabled(true);
654 track->setForced(true);
655 } else if (fileName == "handbrake-chapters-2.mkv") {
656 // remove 2nd tag
657 m_fileInfo.removeTag(m_fileInfo.tags().at(1));
658 }
659 Tag *firstTag = m_fileInfo.tags().at(0);
660 firstTag->setValue(KnownField::Title, m_testTitle);
661 firstTag->setValue(KnownField::Comment, m_testComment);
662 // add an additional tag targeting the first track
664 trackIds.emplace_back(m_fileInfo.tracks().at(0)->id());
665 Tag *newTag = container->createTag(TagTarget(30, trackIds));
666 CPPUNIT_ASSERT_MESSAGE("create tag", newTag);
667 newTag->setValue(KnownField::Album, m_testAlbum);
668 newTag->setValue(KnownField::PartNumber, m_testPartNumber);
669 newTag->setValue(KnownField::TotalParts, m_testTotalParts);
670 // assign an attachment
671 AbstractAttachment *const attachment = container->createAttachment();
672 CPPUNIT_ASSERT_MESSAGE("create attachment", attachment);
673 attachment->setFile(testFilePath("matroska_wave1/logo3_256x256.png"), m_diag, m_progress);
674 attachment->setMimeType("image/png");
675 attachment->setName("cover.jpg");
676}
677
682{
683 cerr << endl << "Matroska parser" << endl;
684 m_fileInfo.setForceFullParse(false);
685 m_tagStatus = TagStatus::Original;
686 parseFile(testFilePath("matroska_wave1/test1.mkv"), &OverallTests::checkMkvTestfile1);
687 parseFile(testFilePath("matroska_wave1/test2.mkv"), &OverallTests::checkMkvTestfile2);
688 parseFile(testFilePath("matroska_wave1/test3.mkv"), &OverallTests::checkMkvTestfile3);
689 parseFile(testFilePath("matroska_wave1/test4.mkv"), &OverallTests::checkMkvTestfile4);
690 parseFile(testFilePath("matroska_wave1/test5.mkv"), &OverallTests::checkMkvTestfile5);
691 parseFile(testFilePath("matroska_wave1/test6.mkv"), &OverallTests::checkMkvTestfile6);
692 parseFile(testFilePath("matroska_wave1/test7.mkv"), &OverallTests::checkMkvTestfile7);
693 parseFile(testFilePath("matroska_wave1/test8.mkv"), &OverallTests::checkMkvTestfile8);
694 parseFile(testFilePath("mtx-test-data/mkv/handbrake-chapters-2.mkv"), &OverallTests::checkMkvTestfileHandbrakeChapters);
695 parseFile(testFilePath("mkv/nested-tags.mkv"), &OverallTests::checkMkvTestfileNestedTags);
696}
697
706{
707 // full parse is required to determine padding
708 m_fileInfo.setForceFullParse(true);
709
710 // do the test under different conditions
711 for (m_mode = 0; m_mode != 0x100; ++m_mode) {
712 using namespace MkvTestFlags;
713
714 // setup test conditions
715 m_fileInfo.setForceRewrite(m_mode & ForceRewring);
716 if (m_mode & KeepTagPos) {
717 m_fileInfo.setTagPosition(ElementPosition::Keep);
718 } else {
719 m_fileInfo.setTagPosition(m_mode & TagsBeforeData ? ElementPosition::BeforeData : ElementPosition::AfterData);
720 }
721 if (m_mode & KeepIndexPos) {
722 if (m_mode & IndexBeforeData) {
723 continue;
724 }
725 m_fileInfo.setIndexPosition(ElementPosition::Keep);
726 } else {
727 m_fileInfo.setIndexPosition(m_mode & IndexBeforeData ? ElementPosition::BeforeData : ElementPosition::AfterData);
728 }
729 m_fileInfo.setPreferredPadding(m_mode & PaddingConstraints ? 4096 : 0);
730 m_fileInfo.setMinPadding(m_mode & PaddingConstraints ? 1024 : 0);
731 m_fileInfo.setMaxPadding(m_mode & PaddingConstraints ? (4096 + 1024) : numeric_limits<size_t>::max());
732 m_fileInfo.setForceTagPosition(m_mode & ForceTagPos);
733 m_fileInfo.setForceIndexPosition(m_mode & ForceIndexPos);
734
735 // print test conditions
736 list<string> testConditions;
737 if (m_mode & ForceRewring) {
738 testConditions.emplace_back("forcing rewrite");
739 }
740 if (m_mode & KeepTagPos) {
741 if (m_mode & RemoveTag) {
742 testConditions.emplace_back("removing tag");
743 } else {
744 testConditions.emplace_back("keeping tag position");
745 }
746 } else if (m_mode & TagsBeforeData) {
747 testConditions.emplace_back("tags before data");
748 } else {
749 testConditions.emplace_back("tags after data");
750 }
751 if (m_mode & KeepIndexPos) {
752 testConditions.emplace_back("keeping index position");
753 } else if (m_mode & IndexBeforeData) {
754 testConditions.emplace_back("index before data");
755 } else {
756 testConditions.emplace_back("index after data");
757 }
758 if (m_mode & PaddingConstraints) {
759 testConditions.emplace_back("padding constraints");
760 }
761 if (m_mode & ForceTagPos) {
762 testConditions.emplace_back("forcing tag position");
763 }
764 if (m_mode & ForceIndexPos) {
765 testConditions.emplace_back("forcing index position");
766 }
767 cerr << endl << "Matroska maker - testmode " << m_mode << ": " << joinStrings(testConditions, ", ") << endl;
768
769 // do actual tests
771 void (OverallTests::*modifyRoutine)(void) = (m_mode & RemoveTag) ? &OverallTests::removeAllTags : &OverallTests::setMkvTestMetaData;
772 makeFile(workingCopyPath("matroska_wave1/test1.mkv"), modifyRoutine, &OverallTests::checkMkvTestfile1);
773 makeFile(workingCopyPath("matroska_wave1/test2.mkv"), modifyRoutine, &OverallTests::checkMkvTestfile2);
774 makeFile(workingCopyPath("matroska_wave1/test3.mkv"), modifyRoutine, &OverallTests::checkMkvTestfile3);
775 makeFile(workingCopyPath("matroska_wave1/test4.mkv"), modifyRoutine, &OverallTests::checkMkvTestfile4);
776 makeFile(workingCopyPath("matroska_wave1/test5.mkv"), modifyRoutine, &OverallTests::checkMkvTestfile5);
777 makeFile(workingCopyPath("matroska_wave1/test6.mkv"), modifyRoutine, &OverallTests::checkMkvTestfile6);
778 makeFile(workingCopyPath("matroska_wave1/test7.mkv"), modifyRoutine, &OverallTests::checkMkvTestfile7);
779 makeFile(workingCopyPath("matroska_wave1/test8.mkv"), modifyRoutine, &OverallTests::checkMkvTestfile8);
780 makeFile(workingCopyPath("mtx-test-data/mkv/handbrake-chapters-2.mkv"), modifyRoutine, &OverallTests::checkMkvTestfileHandbrakeChapters);
781 }
782}
783
789{
790 cerr << endl << "Matroska maker - rewrite file with nested tags" << endl;
791 m_fileInfo.setMinPadding(0);
792 m_fileInfo.setMaxPadding(0);
793 m_fileInfo.setTagPosition(ElementPosition::BeforeData);
794 m_fileInfo.setIndexPosition(ElementPosition::BeforeData);
795 makeFile(workingCopyPath("mkv/nested-tags.mkv"), &OverallTests::noop, &OverallTests::checkMkvTestfileNestedTags);
796}
void testMkvMakingNestedTags()
Tests making a Matroska file with nested tags via MediaFileInfo.
void testMkvParsing()
Tests the Matroska parser via MediaFileInfo.
void testMkvMakingWithDifferentSettings()
Tests the Matroska maker via MediaFileInfo.
void setFile(std::string_view path, Diagnostics &diag, AbortableProgressFeedback &progress)
Sets the data, name and MIME-type for the specified path.
void setName(std::string_view name)
Sets the (file) name of the attachment.
void setMimeType(std::string_view mimeType)
Sets the MIME-type of the attachment.
void setEnabled(bool enabled)
Sets whether the track is enabled.
void setDefault(bool isDefault)
Sets whether the track is a default track.
void setName(std::string_view name)
Sets the name.
void setForced(bool forced)
Sets whether the track is forced.
void setLocale(const Locale &locale)
Sets the locale of the track.
std::uint64_t startOffset() const
Returns the absolute start offset of the data block in the stream.
std::uint64_t size() const
Returns the size of the data block.
std::istream & stream() const
Returns the associated stream.
std::vector< IdType > IdContainerType
Definition tagtarget.h:23
std::uint64_t IdType
Definition tagtarget.h:22
virtual bool setValue(KnownField field, const TagValue &value)=0
Assigns the given value to the specified field.
@ Original
Definition overall.h:28
@ Removed
Definition overall.h:28
@ TestMetaDataPresent
Definition overall.h:28