Tag Parser  6.4.0
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
overallmkv.cpp
Go to the documentation of this file.
1 #include "./overall.h"
2 
3 #include "../abstracttrack.h"
4 #include "../mpegaudio/mpegaudioframe.h"
5 #include "../mp4/mp4ids.h"
6 #include "../matroska/matroskacontainer.h"
7 
8 #include <c++utilities/conversion/binaryconversion.h>
9 #include <c++utilities/io/misc.h>
10 
11 #include <fstream>
12 #include <cstring>
13 
14 namespace MkvTestFlags {
16 {
17  ForceRewring = 0x1,
18  KeepTagPos = 0x2,
21  KeepIndexPos = 0x4,
24  ForceTagPos = 0x10,
25  ForceIndexPos = 0x20,
26 };
27 }
28 
32 void OverallTests::checkMkvTestfile1()
33 {
34  CPPUNIT_ASSERT(m_fileInfo.containerFormat() == ContainerFormat::Matroska);
35  const auto tracks = m_fileInfo.tracks();
36  CPPUNIT_ASSERT_EQUAL(2_st, tracks.size());
37  for(const auto &track : tracks) {
38  switch(track->id()) {
39  case 2422994868:
40  CPPUNIT_ASSERT_EQUAL(MediaType::Video, track->mediaType());
41  CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::MicrosoftMpeg4, track->format().general);
42  break;
43  case 3653291187:
44  CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
45  CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Mpeg1Audio, track->format().general);
46  CPPUNIT_ASSERT_EQUAL(48000u, track->samplingFrequency());
47  break;
48  default:
49  CPPUNIT_FAIL("unknown track ID");
50  }
51  }
52  const auto tags = m_fileInfo.tags();
53  switch(m_tagStatus) {
55  CPPUNIT_ASSERT(tags.size() == 1);
56  CPPUNIT_ASSERT(tags.front()->value(KnownField::Title).toString() == "Big Buck Bunny - test 1");
57  CPPUNIT_ASSERT(tags.front()->value(KnownField::Artist).isEmpty());
58  CPPUNIT_ASSERT(tags.front()->value(KnownField::Comment).toString() == "Matroska Validation File1, basic MPEG4.2 and MP3 with only SimpleBlock");
59  CPPUNIT_ASSERT(tags.front()->value(KnownField::Year).toString() == "2010");
60  break;
62  checkMkvTestMetaData();
63  break;
64  case TagStatus::Removed:
65  CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
66  }
67 }
68 
72 void OverallTests::checkMkvTestfile2()
73 {
74  CPPUNIT_ASSERT(m_fileInfo.containerFormat() == ContainerFormat::Matroska);
75  const auto tracks = m_fileInfo.tracks();
76  CPPUNIT_ASSERT(tracks.size() == 2);
77  for(const auto &track : tracks) {
78  switch(track->id()) {
79  case 1863976627:
80  CPPUNIT_ASSERT(track->mediaType() == MediaType::Video);
81  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Avc);
82  CPPUNIT_ASSERT(track->displaySize() == Size(1354, 576));
83  break;
84  case 3134325680:
85  CPPUNIT_ASSERT(track->mediaType() == MediaType::Audio);
86  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Aac);
87  CPPUNIT_ASSERT(track->samplingFrequency() == 48000);
88  break;
89  default:
90  CPPUNIT_FAIL("unknown track ID");
91  }
92  }
93  const auto tags = m_fileInfo.tags();
94  switch(m_tagStatus) {
96  CPPUNIT_ASSERT(tags.size() == 1);
97  CPPUNIT_ASSERT(tags.front()->value(KnownField::Title).toString() == "Elephant Dream - test 2");
98  CPPUNIT_ASSERT(tags.front()->value(KnownField::Artist).isEmpty());
99  CPPUNIT_ASSERT(tags.front()->value(KnownField::Comment).toString() == "Matroska Validation File 2, 100,000 timecode scale, odd aspect ratio, and CRC-32. Codecs are AVC and AAC");
100  break;
102  checkMkvTestMetaData();
103  break;
104  case TagStatus::Removed:
105  CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
106  }
107 }
108 
112 void OverallTests::checkMkvTestfile3()
113 {
114  CPPUNIT_ASSERT(m_fileInfo.containerFormat() == ContainerFormat::Matroska);
115  const auto tracks = m_fileInfo.tracks();
116  CPPUNIT_ASSERT(tracks.size() == 2);
117  for(const auto &track : tracks) {
118  switch(track->id()) {
119  case 3927961528:
120  CPPUNIT_ASSERT(track->mediaType() == MediaType::Video);
121  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Avc);
122  CPPUNIT_ASSERT(track->displaySize() == Size(1024, 576));
123  break;
124  case 3391885737:
125  CPPUNIT_ASSERT(track->mediaType() == MediaType::Audio);
126  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Mpeg1Audio);
127  CPPUNIT_ASSERT(track->samplingFrequency() == 48000);
128  break;
129  default:
130  CPPUNIT_FAIL("unknown track ID");
131  }
132  }
133  const auto tags = m_fileInfo.tags();
134  switch(m_tagStatus) {
135  case TagStatus::Original:
136  CPPUNIT_ASSERT(tags.size() == 1);
137  CPPUNIT_ASSERT(tags.front()->value(KnownField::Title).toString() == "Elephant Dream - test 3");
138  CPPUNIT_ASSERT(tags.front()->value(KnownField::Artist).isEmpty());
139  CPPUNIT_ASSERT(tags.front()->value(KnownField::Comment).toString() == "Matroska Validation File 3, header stripping on the video track and no SimpleBlock");
140  break;
142  checkMkvTestMetaData();
143  break;
144  case TagStatus::Removed:
145  CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
146  }
147 }
148 
154 void OverallTests::checkMkvTestfile4()
155 {
156  CPPUNIT_ASSERT(m_fileInfo.containerFormat() == ContainerFormat::Matroska);
157  // this file is messed up, it should contain tags but it doesn't
158  const auto tracks = m_fileInfo.tracks();
159  CPPUNIT_ASSERT(tracks.size() == 2);
160  for(const auto &track : tracks) {
161  switch(track->id()) {
162  case 1368622492:
163  CPPUNIT_ASSERT(track->mediaType() == MediaType::Video);
164  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Theora);
165  CPPUNIT_ASSERT(track->displaySize() == Size(1280, 720));
166  break;
167  case 3171450505:
168  CPPUNIT_ASSERT(track->mediaType() == MediaType::Audio);
169  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Vorbis);
170  CPPUNIT_ASSERT(track->samplingFrequency() == 48000);
171  CPPUNIT_ASSERT(track->channelCount() == 2);
172  switch(m_tagStatus) {
173  case TagStatus::Original:
174  case TagStatus::Removed:
175  CPPUNIT_ASSERT_EQUAL("und"s, track->language());
176  CPPUNIT_ASSERT_EQUAL(string(), track->name());
177  CPPUNIT_ASSERT(track->isEnabled());
178  CPPUNIT_ASSERT(!track->isForced());
179  CPPUNIT_ASSERT(!track->isDefault());
180  break;
182  CPPUNIT_ASSERT_EQUAL("ger"s, track->language());
183  CPPUNIT_ASSERT_EQUAL("the name"s, track->name());
184  CPPUNIT_ASSERT(track->isEnabled());
185  CPPUNIT_ASSERT(track->isForced());
186  CPPUNIT_ASSERT(track->isDefault());
187  break;
188  }
189  break;
190  default:
191  CPPUNIT_FAIL("unknown track ID");
192  }
193  }
194  const auto tags = m_fileInfo.tags();
195  switch(m_tagStatus) {
196  case TagStatus::Original:
197  case TagStatus::Removed:
198  CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
199  break;
201  checkMkvTestMetaData();
202  break;
203  }
204 }
205 
209 void OverallTests::checkMkvTestfile5()
210 {
211  CPPUNIT_ASSERT(m_fileInfo.containerFormat() == ContainerFormat::Matroska);
212  const auto tracks = m_fileInfo.tracks();
213  CPPUNIT_ASSERT(tracks.size() == 11);
214  for(const auto &track : tracks) {
215  switch(track->id()) {
216  case 1258329745:
217  CPPUNIT_ASSERT(track->mediaType() == MediaType::Video);
218  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Avc);
219  CPPUNIT_ASSERT(track->displaySize() == Size(1024, 576));
220  break;
221  case 3452711582:
222  CPPUNIT_ASSERT(track->mediaType() == MediaType::Audio);
223  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Aac);
224  CPPUNIT_ASSERT(track->samplingFrequency() == 48000);
225  CPPUNIT_ASSERT(track->channelConfig() == Mpeg4ChannelConfigs::FrontLeftFrontRight);
226  break;
227  case 3554194305:
228  CPPUNIT_ASSERT(track->mediaType() == MediaType::Text);
229  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::TextSubtitle);
230  CPPUNIT_ASSERT(track->language() == "ger");
231  break;
232  default:
233  ;
234  }
235  }
236  const auto tags = m_fileInfo.tags();
237  switch(m_tagStatus) {
238  case TagStatus::Original:
239  CPPUNIT_ASSERT(tags.size() == 1);
240  CPPUNIT_ASSERT(tags.front()->value(KnownField::Title).toString() == "Big Buck Bunny - test 8");
241  CPPUNIT_ASSERT(tags.front()->value(KnownField::Artist).isEmpty());
242  CPPUNIT_ASSERT(tags.front()->value(KnownField::Comment).toString() == "Matroska Validation File 8, secondary audio commentary track, misc subtitle tracks");
243  break;
245  checkMkvTestMetaData();
246  break;
247  case TagStatus::Removed:
248  CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
249  }
250 }
251 
255 void OverallTests::checkMkvTestfile6()
256 {
257  CPPUNIT_ASSERT(m_fileInfo.containerFormat() == ContainerFormat::Matroska);
258  const auto tracks = m_fileInfo.tracks();
259  CPPUNIT_ASSERT(tracks.size() == 2);
260  for(const auto &track : tracks) {
261  switch(track->id()) {
262  case 2422994868:
263  CPPUNIT_ASSERT(track->mediaType() == MediaType::Video);
264  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::MicrosoftMpeg4);
265  CPPUNIT_ASSERT(track->pixelSize() == Size(854, 480));
266  break;
267  case 3653291187:
268  CPPUNIT_ASSERT(track->mediaType() == MediaType::Audio);
269  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Mpeg1Audio);
270  CPPUNIT_ASSERT(track->samplingFrequency() == 48000);
271  CPPUNIT_ASSERT(track->channelConfig() == static_cast<byte>(MpegChannelMode::Stereo));
272  break;
273  default:
274  CPPUNIT_FAIL("unknown track ID");
275  }
276  }
277  const auto tags = m_fileInfo.tags();
278  switch(m_tagStatus) {
279  case TagStatus::Original:
280  CPPUNIT_ASSERT(tags.size() == 1);
281  CPPUNIT_ASSERT(tags.front()->value(KnownField::Title).toString() == "Big Buck Bunny - test 6");
282  CPPUNIT_ASSERT(tags.front()->value(KnownField::Artist).isEmpty());
283  CPPUNIT_ASSERT(tags.front()->value(KnownField::Comment).toString() == "Matroska Validation File 6, random length to code the size of Clusters and Blocks, no Cues for seeking");
284  break;
286  checkMkvTestMetaData();
287  break;
288  case TagStatus::Removed:
289  CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
290  }
291 }
292 
296 void OverallTests::checkMkvTestfile7()
297 {
298  CPPUNIT_ASSERT(m_fileInfo.containerFormat() == ContainerFormat::Matroska);
299  const auto tracks = m_fileInfo.tracks();
300  CPPUNIT_ASSERT(tracks.size() == 2);
301  for(const auto &track : tracks) {
302  switch(track->id()) {
303  case 568001708:
304  CPPUNIT_ASSERT(track->mediaType() == MediaType::Video);
305  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Avc);
306  CPPUNIT_ASSERT(track->pixelSize() == Size(1024, 576));
307  CPPUNIT_ASSERT(!strcmp(track->chromaFormat(), "YUV 4:2:0"));
308  break;
309  case 2088735154:
310  CPPUNIT_ASSERT(track->mediaType() == MediaType::Audio);
311  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Aac);
312  CPPUNIT_ASSERT(track->samplingFrequency() == 48000);
313  CPPUNIT_ASSERT(track->channelConfig() == Mpeg4ChannelConfigs::FrontLeftFrontRight);
314  break;
315  default:
316  CPPUNIT_FAIL("unknown track ID");
317  }
318  }
319  const auto tags = m_fileInfo.tags();
320  switch(m_tagStatus) {
321  case TagStatus::Original:
322  CPPUNIT_ASSERT(tags.size() == 1);
323  CPPUNIT_ASSERT(tags.front()->value(KnownField::Title).toString() == "Big Buck Bunny - test 7");
324  CPPUNIT_ASSERT(tags.front()->value(KnownField::Artist).isEmpty());
325  CPPUNIT_ASSERT(tags.front()->value(KnownField::Comment).toString() == "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");
326  break;
328  checkMkvTestMetaData();
329  break;
330  case TagStatus::Removed:
331  CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
332  }
333 }
334 
338 void OverallTests::checkMkvTestfile8()
339 {
340  CPPUNIT_ASSERT(m_fileInfo.containerFormat() == ContainerFormat::Matroska);
341  const auto tracks = m_fileInfo.tracks();
342  CPPUNIT_ASSERT(tracks.size() == 2);
343  for(const auto &track : tracks) {
344  switch(track->id()) {
345  case 568001708:
346  CPPUNIT_ASSERT(track->mediaType() == MediaType::Video);
347  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Avc);
348  CPPUNIT_ASSERT(track->pixelSize() == Size(1024, 576));
349  CPPUNIT_ASSERT(!strcmp(track->chromaFormat(), "YUV 4:2:0"));
350  break;
351  case 2088735154:
352  CPPUNIT_ASSERT(track->mediaType() == MediaType::Audio);
353  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Aac);
354  CPPUNIT_ASSERT(track->samplingFrequency() == 48000);
355  CPPUNIT_ASSERT(track->channelConfig() == Mpeg4ChannelConfigs::FrontLeftFrontRight);
356  break;
357  default:
358  CPPUNIT_FAIL("unknown track ID");
359  }
360  }
361  const auto tags = m_fileInfo.tags();
362  switch(m_tagStatus) {
363  case TagStatus::Original:
364  CPPUNIT_ASSERT(tags.size() == 1);
365  CPPUNIT_ASSERT(tags.front()->value(KnownField::Title).toString() == "Big Buck Bunny - test 8");
366  CPPUNIT_ASSERT(tags.front()->value(KnownField::Artist).isEmpty());
367  CPPUNIT_ASSERT(tags.front()->value(KnownField::Comment).toString() == "Matroska Validation File 8, audio missing between timecodes 6.019s and 6.360s");
368  break;
370  checkMkvTestMetaData();
371  break;
372  case TagStatus::Removed:
373  CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
374  }
375 }
376 
380 void OverallTests::checkMkvTestfileHandbrakeChapters()
381 {
382  CPPUNIT_ASSERT(m_fileInfo.containerFormat() == ContainerFormat::Matroska);
383  const auto tracks = m_fileInfo.tracks();
384  CPPUNIT_ASSERT_EQUAL(2_st, tracks.size());
385  for(const auto &track : tracks) {
386  switch(track->id()) {
387  case 1:
388  CPPUNIT_ASSERT(track->mediaType() == MediaType::Video);
389  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Avc);
390  CPPUNIT_ASSERT_EQUAL(4.0, track->version());
391  CPPUNIT_ASSERT(track->pixelSize() == Size(1280, 544));
392  CPPUNIT_ASSERT(track->displaySize() == Size(1280, 544));
393  CPPUNIT_ASSERT(track->fps() == 23);
394  break;
395  case 2:
396  CPPUNIT_ASSERT(track->mediaType() == MediaType::Audio);
397  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Aac);
398  CPPUNIT_ASSERT(track->samplingFrequency() == 44100);
399  CPPUNIT_ASSERT(track->channelConfig() == Mpeg4ChannelConfigs::FrontLeftFrontRight);
400  break;
401  default:
402  CPPUNIT_FAIL(argsToString("unknown track ID ", track->id()));
403  }
404  }
405  const auto chapters = m_fileInfo.chapters();
406  CPPUNIT_ASSERT_EQUAL(2_st, chapters.size());
407  for(const auto &chapter : chapters) {
408  switch(chapter->id()) {
409  case 1:
410  CPPUNIT_ASSERT(!strcmp(chapter->names().at(0).data(), "Kapitel 01"));
411  CPPUNIT_ASSERT_EQUAL(0l, chapter->startTime().totalTicks());
412  CPPUNIT_ASSERT_EQUAL(15, chapter->endTime().seconds());
413  break;
414  case 2:
415  CPPUNIT_ASSERT(!strcmp(chapter->names().at(0).data(), "Kapitel 02"));
416  CPPUNIT_ASSERT_EQUAL(15, chapter->startTime().seconds());
417  CPPUNIT_ASSERT_EQUAL(27, chapter->endTime().seconds());
418  break;
419  default:
420  CPPUNIT_FAIL(argsToString("unknown chapter ID ", chapter->id()));
421  }
422  }
423  const auto tags = m_fileInfo.tags();
424  switch(m_tagStatus) {
425  case TagStatus::Original:
426  CPPUNIT_ASSERT_EQUAL(2_st, tags.size());
427  CPPUNIT_ASSERT(tags[0]->target().isEmpty());
428  CPPUNIT_ASSERT_EQUAL(""s, static_cast<MatroskaTag *>(tags[0])->value("CREATION_TIME").toString());
429  CPPUNIT_ASSERT_EQUAL("Lavf55.12.0"s, tags[0]->value(KnownField::Encoder).toString());
430  CPPUNIT_ASSERT_EQUAL(2_st, tags[1]->target().tracks().at(0));
431  CPPUNIT_ASSERT_EQUAL("eng"s, tags[1]->value(KnownField::Language).toString());
432  break;
434  checkMkvTestMetaData();
435  break;
436  case TagStatus::Removed:
437  CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
438  }
439 }
440 
444 void OverallTests::checkMkvTestfileNestedTags()
445 {
446  CPPUNIT_ASSERT(m_fileInfo.containerFormat() == ContainerFormat::Matroska);
447  const auto tags = m_fileInfo.tags();
448  bool generalTagFound = false;
449  switch(m_tagStatus) {
450  case TagStatus::Original:
452  CPPUNIT_ASSERT_EQUAL(5_st, tags.size());
453  for(const Tag *tag : tags) {
454  CPPUNIT_ASSERT(tag->type() == TagType::MatroskaTag);
455  const auto *mkvTag = static_cast<const MatroskaTag *>(tag);
456  const auto &target = mkvTag->target();
457  if(target.level() == 50 && target.tracks().empty()) {
458  generalTagFound = true;
459  CPPUNIT_ASSERT_EQUAL("Vanilla Sky"s, tag->value(KnownField::Title).toString());
460  const auto &fields = mkvTag->fields();
461  const auto &artistField = fields.find(mkvTag->fieldId(KnownField::Artist));
462  CPPUNIT_ASSERT(artistField != fields.end());
463  CPPUNIT_ASSERT_EQUAL("Test artist"s, artistField->second.value().toString());
464  const auto &nestedFields = artistField->second.nestedFields();
465  CPPUNIT_ASSERT_EQUAL(1_st, nestedFields.size());
466  CPPUNIT_ASSERT_EQUAL("ADDRESS"s, nestedFields[0].idToString());
467  CPPUNIT_ASSERT_EQUAL("Test address"s, nestedFields[0].value().toString());
468  }
469  }
470  CPPUNIT_ASSERT(generalTagFound);
471  break;
472  case TagStatus::Removed:
473  CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
474  }
475 }
476 
480 void OverallTests::checkMkvTestMetaData()
481 {
482  // check tags
483  const auto tags = m_fileInfo.tags();
484  const auto tracks = m_fileInfo.tracks();
485  CPPUNIT_ASSERT_EQUAL(2_st, tags.size());
486  CPPUNIT_ASSERT_EQUAL(m_testTitle.toString(), tags.front()->value(KnownField::Title).toString());
487  CPPUNIT_ASSERT(tags.front()->value(KnownField::Artist).isEmpty());
488  CPPUNIT_ASSERT_EQUAL(m_testComment.toString(), tags.front()->value(KnownField::Comment).toString());
489  CPPUNIT_ASSERT_EQUAL(30_st, tags[1]->target().level());
490  CPPUNIT_ASSERT_EQUAL(tracks.at(0)->id(), tags[1]->target().tracks().at(0));
491  CPPUNIT_ASSERT_EQUAL(m_testAlbum.toString(), tags[1]->value(KnownField::Album).toString());
492  CPPUNIT_ASSERT_EQUAL(m_testPartNumber.toInteger(), tags[1]->value(KnownField::PartNumber).toInteger());
493  CPPUNIT_ASSERT_EQUAL(m_testTotalParts.toInteger(), tags[1]->value(KnownField::TotalParts).toInteger());
494 
495  // check attachments
496  const auto attachments = m_fileInfo.attachments();
497  CPPUNIT_ASSERT_EQUAL(1_st, attachments.size());
498  CPPUNIT_ASSERT(attachments[0]->mimeType() == "image/png");
499  CPPUNIT_ASSERT(attachments[0]->name() == "cover.jpg");
500  const StreamDataBlock *attachmentData = attachments[0]->data();
501  CPPUNIT_ASSERT(attachmentData != nullptr);
502  if (m_testCover.empty()) {
503  m_testCover = readFile(testFilePath("matroska_wave1/logo3_256x256.png"), 20000);
504  }
505  CPPUNIT_ASSERT_EQUAL(m_testCover.size(), static_cast<size_t>(attachmentData->size()));
506  istream &attachmentSteam = attachmentData->stream();
507  attachmentSteam.seekg(attachmentData->startOffset());
508  for (char expectedChar : m_testCover) {
509  CPPUNIT_ASSERT_EQUAL(expectedChar, static_cast<char>(attachmentSteam.get()));
510  }
511 }
512 
516 void OverallTests::checkMkvConstraints()
517 {
518  using namespace MkvTestFlags;
519 
520  CPPUNIT_ASSERT(m_fileInfo.container());
521  if(m_mode & PaddingConstraints) {
522  if(m_mode & ForceRewring) {
523  CPPUNIT_ASSERT_EQUAL(4096_st, m_fileInfo.paddingSize());
524  } else {
525  CPPUNIT_ASSERT(m_fileInfo.paddingSize() >= 1024);
526  CPPUNIT_ASSERT(m_fileInfo.paddingSize() <= (4096 + 1024));
527  }
528  if(!(m_mode & RemoveTag) && (m_expectedTagPos != ElementPosition::Keep) && ((m_mode & ForceRewring) || (m_mode & ForceTagPos))) {
529  CPPUNIT_ASSERT_EQUAL(m_expectedTagPos, m_fileInfo.container()->determineTagPosition());
530  }
531  if((m_expectedIndexPos != ElementPosition::Keep) && ((m_mode & ForceRewring) || (m_mode & ForceIndexPos))) {
532  CPPUNIT_ASSERT_EQUAL(m_expectedIndexPos, m_fileInfo.container()->determineIndexPosition());
533  }
534  }
535 }
536 
540 void OverallTests::setMkvTestMetaData()
541 {
542  CPPUNIT_ASSERT_EQUAL(ContainerFormat::Matroska, m_fileInfo.containerFormat());
543  auto *container = static_cast<MatroskaContainer *>(m_fileInfo.container());
544 
545  // change the present tag
546  const string fileName(m_fileInfo.fileName());
547  if(fileName == "test4.mkv") {
548  // test4.mkv has no tag, so one must be created first
549  container->createTag(TagTarget(50));
550  // also change language, name, forced and default of track "3171450505" to German
551  MatroskaTrack *track = container->trackById(3171450505);
552  CPPUNIT_ASSERT(track);
553  track->setLanguage("ger");
554  track->setName("the name");
555  track->setDefault(true);
556  track->setEnabled(true);
557  track->setForced(true);
558  } else if(fileName == "handbrake-chapters-2.mkv") {
559  // remove 2nd tag
560  m_fileInfo.removeTag(m_fileInfo.tags().at(1));
561  }
562  Tag *firstTag = m_fileInfo.tags().at(0);
563  firstTag->setValue(KnownField::Title, m_testTitle);
564  firstTag->setValue(KnownField::Comment, m_testComment);
565  // add an additional tag targeting the first track
567  trackIds.emplace_back(m_fileInfo.tracks().at(0)->id());
568  Tag *newTag = container->createTag(TagTarget(30, trackIds));
569  CPPUNIT_ASSERT_MESSAGE("create tag", newTag);
570  newTag->setValue(KnownField::Album, m_testAlbum);
571  newTag->setValue(KnownField::PartNumber, m_testPartNumber);
572  newTag->setValue(KnownField::TotalParts, m_testTotalParts);
573  // assign an attachment
574  AbstractAttachment *attachment = container->createAttachment();
575  CPPUNIT_ASSERT_MESSAGE("create attachment", attachment);
576  attachment->setFile(TestUtilities::testFilePath("matroska_wave1/logo3_256x256.png"));
577  attachment->setMimeType("image/png");
578  attachment->setName("cover.jpg");
579 }
580 
586 void OverallTests::createMkvWithNestedTags()
587 {
588 #ifdef PLATFORM_UNIX
589  m_nestedTagsMkvPath = workingCopyPathMode("mtx-test-data/mkv/nested-tags.mkv", WorkingCopyMode::NoCopy);
590  remove(m_nestedTagsMkvPath.data());
591 
592  cerr << "\n\n- Create testfile \"" << m_nestedTagsMkvPath << "\" with mkvmerge" << endl;
593  const string tagsMkvPath(testFilePath("mtx-test-data/mkv/tags.mkv"));
594  const string tagsXmlPath(testFilePath("mkv/nested-tags.xml"));
595  const char *const mkvmergeArgs[] = {
596  "--ui-language en_US",
597  "--output", m_nestedTagsMkvPath.data(),
598  "--no-global-tags", "--language", "0:und", "--default-track", "0:yes", "--language", "1:und", "--default-track", "1:yes",
599  "(", tagsMkvPath.data(), ")",
600  "--global-tags", tagsXmlPath.data(), "--track-order", "0:0,0:1", nullptr
601  };
602  string mkvmergeOutput, mkvmergeErrors;
603  int res = execHelperApp("/bin/mkvmerge", mkvmergeArgs, mkvmergeOutput, mkvmergeErrors);
604  cout << mkvmergeOutput << endl;
605  cerr << mkvmergeErrors << endl;
606  if(res) {
607  cerr << "- failure (exit code " << res << "); unable to test nested tags" << endl;
608  remove(m_nestedTagsMkvPath.data());
609  m_nestedTagsMkvPath.clear();
610  }
611 #endif
612 }
613 
618 {
619  cerr << endl << "Matroska parser" << endl;
620  m_fileInfo.setForceFullParse(false);
621  m_tagStatus = TagStatus::Original;
622  parseFile(TestUtilities::testFilePath("matroska_wave1/test1.mkv"), &OverallTests::checkMkvTestfile1);
623  parseFile(TestUtilities::testFilePath("matroska_wave1/test2.mkv"), &OverallTests::checkMkvTestfile2);
624  parseFile(TestUtilities::testFilePath("matroska_wave1/test3.mkv"), &OverallTests::checkMkvTestfile3);
625  parseFile(TestUtilities::testFilePath("matroska_wave1/test4.mkv"), &OverallTests::checkMkvTestfile4);
626  parseFile(TestUtilities::testFilePath("matroska_wave1/test5.mkv"), &OverallTests::checkMkvTestfile5);
627  parseFile(TestUtilities::testFilePath("matroska_wave1/test6.mkv"), &OverallTests::checkMkvTestfile6);
628  parseFile(TestUtilities::testFilePath("matroska_wave1/test7.mkv"), &OverallTests::checkMkvTestfile7);
629  parseFile(TestUtilities::testFilePath("matroska_wave1/test8.mkv"), &OverallTests::checkMkvTestfile8);
630  parseFile(TestUtilities::testFilePath("mtx-test-data/mkv/handbrake-chapters-2.mkv"), &OverallTests::checkMkvTestfileHandbrakeChapters);
631  createMkvWithNestedTags();
632  if(!m_nestedTagsMkvPath.empty()) {
633  parseFile(m_nestedTagsMkvPath, &OverallTests::checkMkvTestfileNestedTags);
634  }
635 }
636 
637 #ifdef PLATFORM_UNIX
638 
645 void OverallTests::testMkvMakingWithDifferentSettings()
646 {
647  // full parse is required to determine padding
648  m_fileInfo.setForceFullParse(true);
649 
650  // do the test under different conditions
651  for(m_mode = 0; m_mode != 0x100; ++m_mode) {
652  using namespace MkvTestFlags;
653 
654  // setup test conditions
655  m_fileInfo.setForceRewrite(m_mode & ForceRewring);
656  if(m_mode & KeepTagPos) {
657  m_fileInfo.setTagPosition(ElementPosition::Keep);
658  } else {
659  m_fileInfo.setTagPosition(m_mode & TagsBeforeData ? ElementPosition::BeforeData : ElementPosition::AfterData);
660  }
661  if(m_mode & KeepIndexPos) {
662  if(m_mode & IndexBeforeData) {
663  continue;
664  }
665  m_fileInfo.setIndexPosition(ElementPosition::Keep);
666  } else {
667  m_fileInfo.setIndexPosition(m_mode & IndexBeforeData ? ElementPosition::BeforeData : ElementPosition::AfterData);
668  }
669  m_fileInfo.setPreferredPadding(m_mode & PaddingConstraints ? 4096 : 0);
670  m_fileInfo.setMinPadding(m_mode & PaddingConstraints ? 1024 : 0);
671  m_fileInfo.setMaxPadding(m_mode & PaddingConstraints ? (4096 + 1024) : static_cast<size_t>(-1));
672  m_fileInfo.setForceTagPosition(m_mode & ForceTagPos);
673  m_fileInfo.setForceIndexPosition(m_mode & ForceIndexPos);
674 
675  // print test conditions
676  list<string> testConditions;
677  if(m_mode & ForceRewring) {
678  testConditions.emplace_back("forcing rewrite");
679  }
680  if(m_mode & KeepTagPos) {
681  if(m_mode & RemoveTag) {
682  testConditions.emplace_back("removing tag");
683  } else {
684  testConditions.emplace_back("keeping tag position");
685  }
686  } else if(m_mode & TagsBeforeData) {
687  testConditions.emplace_back("tags before data");
688  } else {
689  testConditions.emplace_back("tags after data");
690  }
691  if(m_mode & KeepIndexPos) {
692  testConditions.emplace_back("keeping index position");
693  } else if(m_mode & IndexBeforeData) {
694  testConditions.emplace_back("index before data");
695  } else {
696  testConditions.emplace_back("index after data");
697  }
698  if(m_mode & PaddingConstraints) {
699  testConditions.emplace_back("padding constraints");
700  }
701  if(m_mode & ForceTagPos) {
702  testConditions.emplace_back("forcing tag position");
703  }
704  if(m_mode & ForceIndexPos) {
705  testConditions.emplace_back("forcing index position");
706  }
707  cerr << endl << "Matroska maker - testmode " << m_mode << ": " << joinStrings(testConditions, ", ") << endl;
708 
709  // do actual tests
710  m_tagStatus = (m_mode & RemoveTag) ? TagStatus::Removed : TagStatus::TestMetaDataPresent;
711  void (OverallTests::*modifyRoutine)(void) = (m_mode & RemoveTag) ? &OverallTests::removeAllTags : &OverallTests::setMkvTestMetaData;
712  makeFile(TestUtilities::workingCopyPath("matroska_wave1/test1.mkv"), modifyRoutine, &OverallTests::checkMkvTestfile1);
713  makeFile(TestUtilities::workingCopyPath("matroska_wave1/test2.mkv"), modifyRoutine, &OverallTests::checkMkvTestfile2);
714  makeFile(TestUtilities::workingCopyPath("matroska_wave1/test3.mkv"), modifyRoutine, &OverallTests::checkMkvTestfile3);
715  makeFile(TestUtilities::workingCopyPath("matroska_wave1/test4.mkv"), modifyRoutine, &OverallTests::checkMkvTestfile4);
716  makeFile(TestUtilities::workingCopyPath("matroska_wave1/test5.mkv"), modifyRoutine, &OverallTests::checkMkvTestfile5);
717  makeFile(TestUtilities::workingCopyPath("matroska_wave1/test6.mkv"), modifyRoutine, &OverallTests::checkMkvTestfile6);
718  makeFile(TestUtilities::workingCopyPath("matroska_wave1/test7.mkv"), modifyRoutine, &OverallTests::checkMkvTestfile7);
719  makeFile(TestUtilities::workingCopyPath("matroska_wave1/test8.mkv"), modifyRoutine, &OverallTests::checkMkvTestfile8);
720  makeFile(TestUtilities::workingCopyPath("mtx-test-data/mkv/handbrake-chapters-2.mkv"), modifyRoutine, &OverallTests::checkMkvTestfileHandbrakeChapters);
721  }
722 }
723 
728 void OverallTests::testMkvMakingNestedTags()
729 {
730  createMkvWithNestedTags();
731  if(!m_nestedTagsMkvPath.empty()) {
732  cerr << endl << "Matroska maker - rewrite file with nested tags" << endl;
733  m_fileInfo.setMinPadding(0);
734  m_fileInfo.setMaxPadding(0);
735  m_fileInfo.setTagPosition(ElementPosition::BeforeData);
736  m_fileInfo.setIndexPosition(ElementPosition::BeforeData);
737  makeFile(m_nestedTagsMkvPath, &OverallTests::noop, &OverallTests::checkMkvTestfileNestedTags);
738  }
739 }
740 #endif
741 
std::vector< IdType > IdContainerType
Definition: tagtarget.h:35
const TagTarget & target() const
Returns the target of tag.
Definition: tag.h:245
void setFile(const std::string &path)
Sets the data, name and MIME-type for the specified path.
void setDefault(bool isDefault)
Sets whether the track is a default track.
Implementation of GenericContainer<MediaFileInfo, MatroskaTag, MatroskaTrack, EbmlElement>.
The Size class defines the size of a two-dimensional object using integer point precision.
Definition: size.h:16
void setForced(bool forced)
Sets whether the track is forced.
The StreamDataBlock class is a reference to a certain data block of a stream.
void setEnabled(bool enabled)
Sets whether the track is enabled.
std::istream::pos_type startOffset() const
Returns the absolute start offset of the data block in the stream.
The AbstractAttachment class parses and stores attachment information.
The OverallTests class tests reading and writing tags and parsing technical information for all suppo...
Definition: overall.h:44
Implementation of Media::AbstractTrack for the Matroska container.
Definition: matroskatrack.h:47
The Tag class is used to store, read and write tag information.
Definition: tag.h:98
void setName(const std::string &name)
Sets the name.
void testMkvParsing()
Tests the Matroska parser via MediaFileInfo.
Definition: overallmkv.cpp:617
std::istream & stream() const
Returns the associated stream.
Implementation of Media::Tag for the Matroska container.
Definition: matroskatag.h:50
void setName(const std::string &name)
Sets the (file) name of the attachment.
void setMimeType(const std::string &mimeType)
Sets the MIME-type of the attachment.
virtual bool setValue(KnownField field, const TagValue &value)=0
Assigns the given value to the specified field.
The TagTarget class specifies the target of a tag.
Definition: tagtarget.h:31
std::istream::pos_type size() const
Returns the size of the data block.
TagType * createTag(const TagTarget &target=TagTarget())
Creates and returns a tag for the specified target.
void setLanguage(const std::string &language)
Sets the language of the track.