Tag Parser  6.3.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(tracks.size() == 2);
37  for(const auto &track : tracks) {
38  switch(track->id()) {
39  case 2422994868:
40  CPPUNIT_ASSERT(track->mediaType() == MediaType::Video);
41  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::MicrosoftMpeg4);
42  break;
43  case 3653291187:
44  CPPUNIT_ASSERT(track->mediaType() == MediaType::Audio);
45  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Mpeg1Audio);
46  CPPUNIT_ASSERT(track->samplingFrequency() == 48000);
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(tags.size() == 0);
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(tags.size() == 0);
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(tags.size() == 0);
146  }
147 }
148 
152 void OverallTests::checkMkvTestfile4()
153 {
154  CPPUNIT_ASSERT(m_fileInfo.containerFormat() == ContainerFormat::Matroska);
155  // this file is messed up, it should contain tags but it doesn't
156  const auto tracks = m_fileInfo.tracks();
157  CPPUNIT_ASSERT(tracks.size() == 2);
158  for(const auto &track : tracks) {
159  switch(track->id()) {
160  case 1368622492:
161  CPPUNIT_ASSERT(track->mediaType() == MediaType::Video);
162  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Theora);
163  CPPUNIT_ASSERT(track->displaySize() == Size(1280, 720));
164  break;
165  case 3171450505:
166  CPPUNIT_ASSERT(track->mediaType() == MediaType::Audio);
167  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Vorbis);
168  CPPUNIT_ASSERT(track->samplingFrequency() == 48000);
169  CPPUNIT_ASSERT(track->channelCount() == 2);
170  break;
171  default:
172  CPPUNIT_FAIL("unknown track ID");
173  }
174  }
175  const auto tags = m_fileInfo.tags();
176  switch(m_tagStatus) {
177  case TagStatus::Original:
178  case TagStatus::Removed:
179  CPPUNIT_ASSERT(tags.size() == 0);
180  break;
182  checkMkvTestMetaData();
183  break;
184  }
185 }
186 
190 void OverallTests::checkMkvTestfile5()
191 {
192  CPPUNIT_ASSERT(m_fileInfo.containerFormat() == ContainerFormat::Matroska);
193  const auto tracks = m_fileInfo.tracks();
194  CPPUNIT_ASSERT(tracks.size() == 11);
195  for(const auto &track : tracks) {
196  switch(track->id()) {
197  case 1258329745:
198  CPPUNIT_ASSERT(track->mediaType() == MediaType::Video);
199  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Avc);
200  CPPUNIT_ASSERT(track->displaySize() == Size(1024, 576));
201  break;
202  case 3452711582:
203  CPPUNIT_ASSERT(track->mediaType() == MediaType::Audio);
204  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Aac);
205  CPPUNIT_ASSERT(track->samplingFrequency() == 48000);
206  CPPUNIT_ASSERT(track->channelConfig() == Mpeg4ChannelConfigs::FrontLeftFrontRight);
207  break;
208  case 3554194305:
209  CPPUNIT_ASSERT(track->mediaType() == MediaType::Text);
210  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::TextSubtitle);
211  CPPUNIT_ASSERT(track->language() == "ger");
212  break;
213  default:
214  ;
215  }
216  }
217  const auto tags = m_fileInfo.tags();
218  switch(m_tagStatus) {
219  case TagStatus::Original:
220  CPPUNIT_ASSERT(tags.size() == 1);
221  CPPUNIT_ASSERT(tags.front()->value(KnownField::Title).toString() == "Big Buck Bunny - test 8");
222  CPPUNIT_ASSERT(tags.front()->value(KnownField::Artist).isEmpty());
223  CPPUNIT_ASSERT(tags.front()->value(KnownField::Comment).toString() == "Matroska Validation File 8, secondary audio commentary track, misc subtitle tracks");
224  break;
226  checkMkvTestMetaData();
227  break;
228  case TagStatus::Removed:
229  CPPUNIT_ASSERT(tags.size() == 0);
230  }
231 }
232 
236 void OverallTests::checkMkvTestfile6()
237 {
238  CPPUNIT_ASSERT(m_fileInfo.containerFormat() == ContainerFormat::Matroska);
239  const auto tracks = m_fileInfo.tracks();
240  CPPUNIT_ASSERT(tracks.size() == 2);
241  for(const auto &track : tracks) {
242  switch(track->id()) {
243  case 2422994868:
244  CPPUNIT_ASSERT(track->mediaType() == MediaType::Video);
245  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::MicrosoftMpeg4);
246  CPPUNIT_ASSERT(track->pixelSize() == Size(854, 480));
247  break;
248  case 3653291187:
249  CPPUNIT_ASSERT(track->mediaType() == MediaType::Audio);
250  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Mpeg1Audio);
251  CPPUNIT_ASSERT(track->samplingFrequency() == 48000);
252  CPPUNIT_ASSERT(track->channelConfig() == static_cast<byte>(MpegChannelMode::Stereo));
253  break;
254  default:
255  CPPUNIT_FAIL("unknown track ID");
256  }
257  }
258  const auto tags = m_fileInfo.tags();
259  switch(m_tagStatus) {
260  case TagStatus::Original:
261  CPPUNIT_ASSERT(tags.size() == 1);
262  CPPUNIT_ASSERT(tags.front()->value(KnownField::Title).toString() == "Big Buck Bunny - test 6");
263  CPPUNIT_ASSERT(tags.front()->value(KnownField::Artist).isEmpty());
264  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");
265  break;
267  checkMkvTestMetaData();
268  break;
269  case TagStatus::Removed:
270  CPPUNIT_ASSERT(tags.size() == 0);
271  }
272 }
273 
277 void OverallTests::checkMkvTestfile7()
278 {
279  CPPUNIT_ASSERT(m_fileInfo.containerFormat() == ContainerFormat::Matroska);
280  const auto tracks = m_fileInfo.tracks();
281  CPPUNIT_ASSERT(tracks.size() == 2);
282  for(const auto &track : tracks) {
283  switch(track->id()) {
284  case 568001708:
285  CPPUNIT_ASSERT(track->mediaType() == MediaType::Video);
286  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Avc);
287  CPPUNIT_ASSERT(track->pixelSize() == Size(1024, 576));
288  CPPUNIT_ASSERT(!strcmp(track->chromaFormat(), "YUV 4:2:0"));
289  break;
290  case 2088735154:
291  CPPUNIT_ASSERT(track->mediaType() == MediaType::Audio);
292  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Aac);
293  CPPUNIT_ASSERT(track->samplingFrequency() == 48000);
294  CPPUNIT_ASSERT(track->channelConfig() == Mpeg4ChannelConfigs::FrontLeftFrontRight);
295  break;
296  default:
297  CPPUNIT_FAIL("unknown track ID");
298  }
299  }
300  const auto tags = m_fileInfo.tags();
301  switch(m_tagStatus) {
302  case TagStatus::Original:
303  CPPUNIT_ASSERT(tags.size() == 1);
304  CPPUNIT_ASSERT(tags.front()->value(KnownField::Title).toString() == "Big Buck Bunny - test 7");
305  CPPUNIT_ASSERT(tags.front()->value(KnownField::Artist).isEmpty());
306  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");
307  break;
309  checkMkvTestMetaData();
310  break;
311  case TagStatus::Removed:
312  CPPUNIT_ASSERT(tags.size() == 0);
313  }
314 }
315 
319 void OverallTests::checkMkvTestfile8()
320 {
321  CPPUNIT_ASSERT(m_fileInfo.containerFormat() == ContainerFormat::Matroska);
322  const auto tracks = m_fileInfo.tracks();
323  CPPUNIT_ASSERT(tracks.size() == 2);
324  for(const auto &track : tracks) {
325  switch(track->id()) {
326  case 568001708:
327  CPPUNIT_ASSERT(track->mediaType() == MediaType::Video);
328  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Avc);
329  CPPUNIT_ASSERT(track->pixelSize() == Size(1024, 576));
330  CPPUNIT_ASSERT(!strcmp(track->chromaFormat(), "YUV 4:2:0"));
331  break;
332  case 2088735154:
333  CPPUNIT_ASSERT(track->mediaType() == MediaType::Audio);
334  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Aac);
335  CPPUNIT_ASSERT(track->samplingFrequency() == 48000);
336  CPPUNIT_ASSERT(track->channelConfig() == Mpeg4ChannelConfigs::FrontLeftFrontRight);
337  break;
338  default:
339  CPPUNIT_FAIL("unknown track ID");
340  }
341  }
342  const auto tags = m_fileInfo.tags();
343  switch(m_tagStatus) {
344  case TagStatus::Original:
345  CPPUNIT_ASSERT(tags.size() == 1);
346  CPPUNIT_ASSERT(tags.front()->value(KnownField::Title).toString() == "Big Buck Bunny - test 8");
347  CPPUNIT_ASSERT(tags.front()->value(KnownField::Artist).isEmpty());
348  CPPUNIT_ASSERT(tags.front()->value(KnownField::Comment).toString() == "Matroska Validation File 8, audio missing between timecodes 6.019s and 6.360s");
349  break;
351  checkMkvTestMetaData();
352  break;
353  case TagStatus::Removed:
354  CPPUNIT_ASSERT(tags.size() == 0);
355  }
356 }
357 
361 void OverallTests::checkMkvTestfileHandbrakeChapters()
362 {
363  CPPUNIT_ASSERT(m_fileInfo.containerFormat() == ContainerFormat::Matroska);
364  const auto tracks = m_fileInfo.tracks();
365  CPPUNIT_ASSERT_EQUAL(2_st, tracks.size());
366  for(const auto &track : tracks) {
367  switch(track->id()) {
368  case 1:
369  CPPUNIT_ASSERT(track->mediaType() == MediaType::Video);
370  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Avc);
371  CPPUNIT_ASSERT_EQUAL(4.0, track->version());
372  CPPUNIT_ASSERT(track->pixelSize() == Size(1280, 544));
373  CPPUNIT_ASSERT(track->displaySize() == Size(1280, 544));
374  CPPUNIT_ASSERT(track->fps() == 23);
375  break;
376  case 2:
377  CPPUNIT_ASSERT(track->mediaType() == MediaType::Audio);
378  CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Aac);
379  CPPUNIT_ASSERT(track->samplingFrequency() == 44100);
380  CPPUNIT_ASSERT(track->channelConfig() == Mpeg4ChannelConfigs::FrontLeftFrontRight);
381  break;
382  default:
383  CPPUNIT_FAIL(argsToString("unknown track ID ", track->id()));
384  }
385  }
386  const auto chapters = m_fileInfo.chapters();
387  CPPUNIT_ASSERT_EQUAL(2_st, chapters.size());
388  for(const auto &chapter : chapters) {
389  switch(chapter->id()) {
390  case 1:
391  CPPUNIT_ASSERT(!strcmp(chapter->names().at(0).data(), "Kapitel 01"));
392  CPPUNIT_ASSERT_EQUAL(0l, chapter->startTime().totalTicks());
393  CPPUNIT_ASSERT_EQUAL(15, chapter->endTime().seconds());
394  break;
395  case 2:
396  CPPUNIT_ASSERT(!strcmp(chapter->names().at(0).data(), "Kapitel 02"));
397  CPPUNIT_ASSERT_EQUAL(15, chapter->startTime().seconds());
398  CPPUNIT_ASSERT_EQUAL(27, chapter->endTime().seconds());
399  break;
400  default:
401  CPPUNIT_FAIL(argsToString("unknown chapter ID ", chapter->id()));
402  }
403  }
404  const auto tags = m_fileInfo.tags();
405  switch(m_tagStatus) {
406  case TagStatus::Original:
407  CPPUNIT_ASSERT_EQUAL(2_st, tags.size());
408  CPPUNIT_ASSERT(tags[0]->target().isEmpty());
409  CPPUNIT_ASSERT_EQUAL(""s, static_cast<MatroskaTag *>(tags[0])->value("CREATION_TIME").toString());
410  CPPUNIT_ASSERT_EQUAL("Lavf55.12.0"s, tags[0]->value(KnownField::Encoder).toString());
411  CPPUNIT_ASSERT_EQUAL(2_st, tags[1]->target().tracks().at(0));
412  CPPUNIT_ASSERT_EQUAL("eng"s, tags[1]->value(KnownField::Language).toString());
413  break;
415  checkMkvTestMetaData();
416  break;
417  case TagStatus::Removed:
418  CPPUNIT_ASSERT(tags.size() == 0);
419  }
420 }
421 
425 void OverallTests::checkMkvTestfileNestedTags()
426 {
427  CPPUNIT_ASSERT(m_fileInfo.containerFormat() == ContainerFormat::Matroska);
428  const auto tags = m_fileInfo.tags();
429  bool generalTagFound = false;
430  switch(m_tagStatus) {
431  case TagStatus::Original:
433  CPPUNIT_ASSERT_EQUAL(5_st, tags.size());
434  for(const Tag *tag : tags) {
435  CPPUNIT_ASSERT(tag->type() == TagType::MatroskaTag);
436  const auto *mkvTag = static_cast<const MatroskaTag *>(tag);
437  const auto &target = mkvTag->target();
438  if(target.level() == 50 && target.tracks().empty()) {
439  generalTagFound = true;
440  CPPUNIT_ASSERT_EQUAL("Vanilla Sky"s, tag->value(KnownField::Title).toString());
441  const auto &fields = mkvTag->fields();
442  const auto &artistField = fields.find(mkvTag->fieldId(KnownField::Artist));
443  CPPUNIT_ASSERT(artistField != fields.end());
444  CPPUNIT_ASSERT_EQUAL("Test artist"s, artistField->second.value().toString());
445  const auto &nestedFields = artistField->second.nestedFields();
446  CPPUNIT_ASSERT_EQUAL(1_st, nestedFields.size());
447  CPPUNIT_ASSERT_EQUAL("ADDRESS"s, nestedFields[0].idToString());
448  CPPUNIT_ASSERT_EQUAL("Test address"s, nestedFields[0].value().toString());
449  }
450  }
451  CPPUNIT_ASSERT(generalTagFound);
452  break;
453  case TagStatus::Removed:
454  CPPUNIT_ASSERT(tags.size() == 0);
455  }
456 }
457 
461 void OverallTests::checkMkvTestMetaData()
462 {
463  // check tags
464  const auto tags = m_fileInfo.tags();
465  const auto tracks = m_fileInfo.tracks();
466  CPPUNIT_ASSERT_EQUAL(2_st, tags.size());
467  CPPUNIT_ASSERT_EQUAL(m_testTitle.toString(), tags.front()->value(KnownField::Title).toString());
468  CPPUNIT_ASSERT(tags.front()->value(KnownField::Artist).isEmpty());
469  CPPUNIT_ASSERT_EQUAL(m_testComment.toString(), tags.front()->value(KnownField::Comment).toString());
470  CPPUNIT_ASSERT_EQUAL(30_st, tags[1]->target().level());
471  CPPUNIT_ASSERT_EQUAL(tracks.at(0)->id(), tags[1]->target().tracks().at(0));
472  CPPUNIT_ASSERT_EQUAL(m_testAlbum.toString(), tags[1]->value(KnownField::Album).toString());
473  CPPUNIT_ASSERT_EQUAL(m_testPartNumber.toInteger(), tags[1]->value(KnownField::PartNumber).toInteger());
474  CPPUNIT_ASSERT_EQUAL(m_testTotalParts.toInteger(), tags[1]->value(KnownField::TotalParts).toInteger());
475 
476  // check attachments
477  const auto attachments = m_fileInfo.attachments();
478  CPPUNIT_ASSERT_EQUAL(1_st, attachments.size());
479  CPPUNIT_ASSERT(attachments[0]->mimeType() == "image/png");
480  CPPUNIT_ASSERT(attachments[0]->name() == "cover.jpg");
481  const StreamDataBlock *attachmentData = attachments[0]->data();
482  CPPUNIT_ASSERT(attachmentData != nullptr);
483  if (m_testCover.empty()) {
484  m_testCover = readFile(testFilePath("matroska_wave1/logo3_256x256.png"), 20000);
485  }
486  CPPUNIT_ASSERT_EQUAL(m_testCover.size(), static_cast<size_t>(attachmentData->size()));
487  istream &attachmentSteam = attachmentData->stream();
488  attachmentSteam.seekg(attachmentData->startOffset());
489  for (char expectedChar : m_testCover) {
490  CPPUNIT_ASSERT_EQUAL(expectedChar, static_cast<char>(attachmentSteam.get()));
491  }
492 }
493 
497 void OverallTests::checkMkvConstraints()
498 {
499  using namespace MkvTestFlags;
500 
501  CPPUNIT_ASSERT(m_fileInfo.container());
502  if(m_mode & PaddingConstraints) {
503  if(m_mode & ForceRewring) {
504  CPPUNIT_ASSERT_EQUAL(4096_st, m_fileInfo.paddingSize());
505  } else {
506  CPPUNIT_ASSERT(m_fileInfo.paddingSize() >= 1024);
507  CPPUNIT_ASSERT(m_fileInfo.paddingSize() <= (4096 + 1024));
508  }
509  if(!(m_mode & RemoveTag) && (m_expectedTagPos != ElementPosition::Keep) && ((m_mode & ForceRewring) || (m_mode & ForceTagPos))) {
510  CPPUNIT_ASSERT_EQUAL(m_expectedTagPos, m_fileInfo.container()->determineTagPosition());
511  }
512  if((m_expectedIndexPos != ElementPosition::Keep) && ((m_mode & ForceRewring) || (m_mode & ForceIndexPos))) {
513  CPPUNIT_ASSERT_EQUAL(m_expectedIndexPos, m_fileInfo.container()->determineIndexPosition());
514  }
515  }
516 }
517 
521 void OverallTests::setMkvTestMetaData()
522 {
523  // change the present tag
524  const string fileName(m_fileInfo.fileName());
525  if(fileName == "test4.mkv") {
526  // test4.mkv has no tag, so one must be created first
527  m_fileInfo.container()->createTag(TagTarget(50));
528  } else if(fileName == "handbrake-chapters-2.mkv") {
529  // remove 2nd tag
530  m_fileInfo.removeTag(m_fileInfo.tags().at(1));
531  }
532  Tag *firstTag = m_fileInfo.tags().at(0);
533  firstTag->setValue(KnownField::Title, m_testTitle);
534  firstTag->setValue(KnownField::Comment, m_testComment);
535  // add an additional tag targeting the first track
537  trackIds.emplace_back(m_fileInfo.tracks().at(0)->id());
538  if(Tag *newTag = m_fileInfo.container()->createTag(TagTarget(30, trackIds))) {
539  newTag->setValue(KnownField::Album, m_testAlbum);
540  newTag->setValue(KnownField::PartNumber, m_testPartNumber);
541  newTag->setValue(KnownField::TotalParts, m_testTotalParts);
542  } else {
543  CPPUNIT_FAIL("can not create tag");
544  }
545  // assign an attachment
546  if(AbstractAttachment *attachment = m_fileInfo.container()->createAttachment()) {
547  attachment->setFile(TestUtilities::testFilePath("matroska_wave1/logo3_256x256.png"));
548  attachment->setMimeType("image/png");
549  attachment->setName("cover.jpg");
550  } else {
551  CPPUNIT_FAIL("can not create attachment");
552  }
553 }
554 
560 void OverallTests::createMkvWithNestedTags()
561 {
562 #ifdef PLATFORM_UNIX
563  m_nestedTagsMkvPath = workingCopyPathMode("mtx-test-data/mkv/nested-tags.mkv", WorkingCopyMode::NoCopy);
564  remove(m_nestedTagsMkvPath.data());
565 
566  cerr << "\n\n- Create testfile \"" << m_nestedTagsMkvPath << "\" with mkvmerge" << endl;
567  const string tagsMkvPath(testFilePath("mtx-test-data/mkv/tags.mkv"));
568  const string tagsXmlPath(testFilePath("mkv/nested-tags.xml"));
569  const char *const mkvmergeArgs[] = {
570  "--ui-language en_US",
571  "--output", m_nestedTagsMkvPath.data(),
572  "--no-global-tags", "--language", "0:und", "--default-track", "0:yes", "--language", "1:und", "--default-track", "1:yes",
573  "(", tagsMkvPath.data(), ")",
574  "--global-tags", tagsXmlPath.data(), "--track-order", "0:0,0:1", nullptr
575  };
576  string mkvmergeOutput, mkvmergeErrors;
577  int res = execHelperApp("/bin/mkvmerge", mkvmergeArgs, mkvmergeOutput, mkvmergeErrors);
578  cout << mkvmergeOutput << endl;
579  cerr << mkvmergeErrors << endl;
580  if(res) {
581  cerr << "- failure (exit code " << res << "); unable to test nested tags" << endl;
582  remove(m_nestedTagsMkvPath.data());
583  m_nestedTagsMkvPath.clear();
584  }
585 #endif
586 }
587 
592 {
593  cerr << endl << "Matroska parser" << endl;
594  m_fileInfo.setForceFullParse(false);
595  m_tagStatus = TagStatus::Original;
596  parseFile(TestUtilities::testFilePath("matroska_wave1/test1.mkv"), &OverallTests::checkMkvTestfile1);
597  parseFile(TestUtilities::testFilePath("matroska_wave1/test2.mkv"), &OverallTests::checkMkvTestfile2);
598  parseFile(TestUtilities::testFilePath("matroska_wave1/test3.mkv"), &OverallTests::checkMkvTestfile3);
599  parseFile(TestUtilities::testFilePath("matroska_wave1/test4.mkv"), &OverallTests::checkMkvTestfile4);
600  parseFile(TestUtilities::testFilePath("matroska_wave1/test5.mkv"), &OverallTests::checkMkvTestfile5);
601  parseFile(TestUtilities::testFilePath("matroska_wave1/test6.mkv"), &OverallTests::checkMkvTestfile6);
602  parseFile(TestUtilities::testFilePath("matroska_wave1/test7.mkv"), &OverallTests::checkMkvTestfile7);
603  parseFile(TestUtilities::testFilePath("matroska_wave1/test8.mkv"), &OverallTests::checkMkvTestfile8);
604  parseFile(TestUtilities::testFilePath("mtx-test-data/mkv/handbrake-chapters-2.mkv"), &OverallTests::checkMkvTestfileHandbrakeChapters);
605  createMkvWithNestedTags();
606  if(!m_nestedTagsMkvPath.empty()) {
607  parseFile(m_nestedTagsMkvPath, &OverallTests::checkMkvTestfileNestedTags);
608  }
609 }
610 
611 #ifdef PLATFORM_UNIX
612 
619 void OverallTests::testMkvMakingWithDifferentSettings()
620 {
621  // full parse is required to determine padding
622  m_fileInfo.setForceFullParse(true);
623 
624  // do the test under different conditions
625  for(m_mode = 0; m_mode != 0x100; ++m_mode) {
626  using namespace MkvTestFlags;
627 
628  // setup test conditions
629  m_fileInfo.setForceRewrite(m_mode & ForceRewring);
630  if(m_mode & KeepTagPos) {
631  m_fileInfo.setTagPosition(ElementPosition::Keep);
632  } else {
633  m_fileInfo.setTagPosition(m_mode & TagsBeforeData ? ElementPosition::BeforeData : ElementPosition::AfterData);
634  }
635  if(m_mode & KeepIndexPos) {
636  if(m_mode & IndexBeforeData) {
637  continue;
638  }
639  m_fileInfo.setIndexPosition(ElementPosition::Keep);
640  } else {
641  m_fileInfo.setIndexPosition(m_mode & IndexBeforeData ? ElementPosition::BeforeData : ElementPosition::AfterData);
642  }
643  m_fileInfo.setPreferredPadding(m_mode & PaddingConstraints ? 4096 : 0);
644  m_fileInfo.setMinPadding(m_mode & PaddingConstraints ? 1024 : 0);
645  m_fileInfo.setMaxPadding(m_mode & PaddingConstraints ? (4096 + 1024) : static_cast<size_t>(-1));
646  m_fileInfo.setForceTagPosition(m_mode & ForceTagPos);
647  m_fileInfo.setForceIndexPosition(m_mode & ForceIndexPos);
648 
649  // print test conditions
650  list<string> testConditions;
651  if(m_mode & ForceRewring) {
652  testConditions.emplace_back("forcing rewrite");
653  }
654  if(m_mode & KeepTagPos) {
655  if(m_mode & RemoveTag) {
656  testConditions.emplace_back("removing tag");
657  } else {
658  testConditions.emplace_back("keeping tag position");
659  }
660  } else if(m_mode & TagsBeforeData) {
661  testConditions.emplace_back("tags before data");
662  } else {
663  testConditions.emplace_back("tags after data");
664  }
665  if(m_mode & KeepIndexPos) {
666  testConditions.emplace_back("keeping index position");
667  } else if(m_mode & IndexBeforeData) {
668  testConditions.emplace_back("index before data");
669  } else {
670  testConditions.emplace_back("index after data");
671  }
672  if(m_mode & PaddingConstraints) {
673  testConditions.emplace_back("padding constraints");
674  }
675  if(m_mode & ForceTagPos) {
676  testConditions.emplace_back("forcing tag position");
677  }
678  if(m_mode & ForceIndexPos) {
679  testConditions.emplace_back("forcing index position");
680  }
681  cerr << endl << "Matroska maker - testmode " << m_mode << ": " << joinStrings(testConditions, ", ") << endl;
682 
683  // do actual tests
684  m_tagStatus = (m_mode & RemoveTag) ? TagStatus::Removed : TagStatus::TestMetaDataPresent;
685  void (OverallTests::*modifyRoutine)(void) = (m_mode & RemoveTag) ? &OverallTests::removeAllTags : &OverallTests::setMkvTestMetaData;
686  makeFile(TestUtilities::workingCopyPath("matroska_wave1/test1.mkv"), modifyRoutine, &OverallTests::checkMkvTestfile1);
687  makeFile(TestUtilities::workingCopyPath("matroska_wave1/test2.mkv"), modifyRoutine, &OverallTests::checkMkvTestfile2);
688  makeFile(TestUtilities::workingCopyPath("matroska_wave1/test3.mkv"), modifyRoutine, &OverallTests::checkMkvTestfile3);
689  makeFile(TestUtilities::workingCopyPath("matroska_wave1/test4.mkv"), modifyRoutine, &OverallTests::checkMkvTestfile4);
690  makeFile(TestUtilities::workingCopyPath("matroska_wave1/test5.mkv"), modifyRoutine, &OverallTests::checkMkvTestfile5);
691  makeFile(TestUtilities::workingCopyPath("matroska_wave1/test6.mkv"), modifyRoutine, &OverallTests::checkMkvTestfile6);
692  makeFile(TestUtilities::workingCopyPath("matroska_wave1/test7.mkv"), modifyRoutine, &OverallTests::checkMkvTestfile7);
693  makeFile(TestUtilities::workingCopyPath("matroska_wave1/test8.mkv"), modifyRoutine, &OverallTests::checkMkvTestfile8);
694  makeFile(TestUtilities::workingCopyPath("mtx-test-data/mkv/handbrake-chapters-2.mkv"), modifyRoutine, &OverallTests::checkMkvTestfileHandbrakeChapters);
695  }
696 }
697 
702 void OverallTests::testMkvMakingNestedTags()
703 {
704  createMkvWithNestedTags();
705  if(!m_nestedTagsMkvPath.empty()) {
706  cerr << endl << "Matroska maker - rewrite file with nested tags" << endl;
707  m_fileInfo.setMinPadding(0);
708  m_fileInfo.setMaxPadding(0);
709  m_fileInfo.setTagPosition(ElementPosition::BeforeData);
710  m_fileInfo.setIndexPosition(ElementPosition::BeforeData);
711  makeFile(m_nestedTagsMkvPath, &OverallTests::noop, &OverallTests::checkMkvTestfileNestedTags);
712  }
713 }
714 #endif
715 
std::vector< IdType > IdContainerType
Definition: tagtarget.h:35
const TagTarget & target() const
Returns the target of tag.
Definition: tag.h:245
The Size class defines the size of a two-dimensional object using integer point precision.
Definition: size.h:16
The StreamDataBlock class is a reference to a certain data block of a stream.
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:43
The Tag class is used to store, read and write tag information.
Definition: tag.h:98
void testMkvParsing()
Tests the Matroska parser via MediaFileInfo.
Definition: overallmkv.cpp:591
std::istream & stream() const
Returns the associated stream.
Implementation of Media::Tag for the Matroska container.
Definition: matroskatag.h:50
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.