Tag Parser  9.1.2
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
overallmp4.cpp
Go to the documentation of this file.
1 #include "./helper.h"
2 #include "./overall.h"
3 
4 #include "../abstracttrack.h"
5 #include "../mp4/mp4container.h"
6 #include "../mp4/mp4ids.h"
7 #include "../mp4/mp4tag.h"
8 
9 using namespace CppUtilities;
10 
11 namespace Mp4TestFlags {
12 enum TestFlag {
13  ForceRewring = 0x1,
14  KeepTagPos = 0x2,
18  ForceTagPos = 0x8,
19 };
20 }
21 
25 void OverallTests::checkMp4Testfile1()
26 {
27  CPPUNIT_ASSERT_EQUAL(ContainerFormat::Mp4, m_fileInfo.containerFormat());
28  const auto tracks = m_fileInfo.tracks();
29  CPPUNIT_ASSERT_EQUAL(1_st, tracks.size());
30  for (const auto &track : tracks) {
31  switch (track->id()) {
32  case 1:
33  CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
34  CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Aac, track->format().general);
35  CPPUNIT_ASSERT_EQUAL(2012, track->creationTime().year());
36  CPPUNIT_ASSERT_EQUAL(44100u, track->samplingFrequency());
37  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(Mpeg4ChannelConfigs::FrontLeftFrontRight), track->channelConfig());
38  break;
39  default:
40  CPPUNIT_FAIL("unknown track ID");
41  }
42  }
43  const auto tags = m_fileInfo.tags();
44  switch (m_tagStatus) {
46  CPPUNIT_ASSERT_EQUAL(1_st, tags.size());
47  CPPUNIT_ASSERT_EQUAL("Danse Macabre, Op.40"s, tags.front()->value(KnownField::Title).toString());
48  CPPUNIT_ASSERT_EQUAL("Saint-SaĆ«ns"s, tags.front()->value(KnownField::Artist).toString());
49  CPPUNIT_ASSERT_EQUAL("Classical"s, tags.front()->value(KnownField::Genre).toString());
50  CPPUNIT_ASSERT_EQUAL(
51  "qaac 1.32, CoreAudioToolbox 7.9.7.3, AAC-LC Encoder, TVBR q63, Quality 96"s, tags.front()->value(KnownField::Encoder).toString());
52  CPPUNIT_ASSERT_EQUAL(10, tags.front()->value(KnownField::TrackPosition).toPositionInSet().position());
53  break;
55  checkMp4TestMetaData();
56  break;
57  case TagStatus::Removed:
58  CPPUNIT_ASSERT_EQUAL(0_st, tracks.size());
59  }
60  CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
61 }
62 
66 void OverallTests::checkMp4Testfile2()
67 {
68  CPPUNIT_ASSERT_EQUAL(ContainerFormat::Mp4, m_fileInfo.containerFormat());
69  const auto tracks = m_fileInfo.tracks();
70  CPPUNIT_ASSERT_EQUAL(5_st, tracks.size());
71  for (const auto &track : tracks) {
72  switch (track->id()) {
73  case 1:
74  CPPUNIT_ASSERT_EQUAL(MediaType::Video, track->mediaType());
75  CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Avc, track->format().general);
76  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(SubFormats::AvcHighProfile), track->format().sub);
77  CPPUNIT_ASSERT_EQUAL(4.0, track->version());
78  CPPUNIT_ASSERT_EQUAL(2013, track->creationTime().year());
79  CPPUNIT_ASSERT(track->pixelSize() == Size(1920, 750));
80  break;
81  case 2:
82  CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
83  CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Aac, track->format().general);
84  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(SubFormats::AacMpeg4LowComplexityProfile), track->format().sub);
85  CPPUNIT_ASSERT(!(track->format().extension & ExtensionFormats::SpectralBandReplication));
86  CPPUNIT_ASSERT(!(track->format().extension & ExtensionFormats::ParametricStereo));
87  CPPUNIT_ASSERT_EQUAL("eng"s, track->language());
88  CPPUNIT_ASSERT_EQUAL(2013, track->creationTime().year());
89  CPPUNIT_ASSERT_EQUAL(48000u, track->samplingFrequency());
90  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(Mpeg4ChannelConfigs::FrontLeftFrontRight), track->channelConfig());
91  break;
92  case 3:
93  CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
94  CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Ac3, track->format().general);
95  CPPUNIT_ASSERT_EQUAL("eng"s, track->language());
96  CPPUNIT_ASSERT_EQUAL(2013, track->creationTime().year());
97  break;
98  case 4:
99  CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
100  CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::DtsHd, track->format().general);
101  CPPUNIT_ASSERT_EQUAL("eng"s, track->language());
102  CPPUNIT_ASSERT_EQUAL(2013, track->creationTime().year());
103  break;
104  case 6:
105  CPPUNIT_ASSERT_EQUAL(MediaType::Text, track->mediaType());
106  CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::TimedText, track->format().general);
107  CPPUNIT_ASSERT_EQUAL(2013, track->creationTime().year());
108  break;
109  default:
110  CPPUNIT_FAIL("unknown track ID");
111  }
112  }
113  const auto tags = m_fileInfo.tags();
114  switch (m_tagStatus) {
115  case TagStatus::Original:
116  CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
117  break;
119  checkMp4TestMetaData();
120  break;
121  case TagStatus::Removed:
122  CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
123  }
124  CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
125 }
126 
130 void OverallTests::checkMp4Testfile3()
131 {
132  CPPUNIT_ASSERT_EQUAL(ContainerFormat::Mp4, m_fileInfo.containerFormat());
133  CPPUNIT_ASSERT(m_fileInfo.container() != nullptr);
134  CPPUNIT_ASSERT_EQUAL("dash"s, m_fileInfo.container()->documentType());
135  const auto tracks = m_fileInfo.tracks();
136  CPPUNIT_ASSERT_EQUAL(1_st, tracks.size());
137  for (const auto &track : tracks) {
138  switch (track->id()) {
139  case 1:
140  CPPUNIT_ASSERT_EQUAL(MediaType::Video, track->mediaType());
141  CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Avc, track->format().general);
142  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(SubFormats::AvcMainProfile), track->format().sub);
143  CPPUNIT_ASSERT_EQUAL(3.1, track->version());
144  CPPUNIT_ASSERT_EQUAL(2014, track->creationTime().year());
145  CPPUNIT_ASSERT_EQUAL(Size(854, 480), track->pixelSize());
146  CPPUNIT_ASSERT_EQUAL("YUV 4:2:0"s, string(track->chromaFormat()));
147  break;
148  default:
149  CPPUNIT_FAIL("unknown track ID");
150  }
151  }
152  const auto tags = m_fileInfo.tags();
153  switch (m_tagStatus) {
154  case TagStatus::Original:
155  CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
156  break;
158  checkMp4TestMetaData();
159  break;
160  case TagStatus::Removed:
161  CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
162  }
163 
164  for (const auto &msg : m_diag) {
165  if (msg.level() != DiagLevel::Warning) {
166  continue;
167  }
168  if (m_mode & Mp4TestFlags::TagsBeforeData) {
169  CPPUNIT_FAIL("No warnings expected when putting tags before data.");
170  } else {
171  CPPUNIT_ASSERT_EQUAL("Sorry, but putting index/tags at the end is not possible when dealing with DASH files."s, msg.message());
172  }
173  }
174  CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Warning);
175 }
176 
180 void OverallTests::checkMp4Testfile4()
181 {
182  CPPUNIT_ASSERT_EQUAL(ContainerFormat::Mp4, m_fileInfo.containerFormat());
183  CPPUNIT_ASSERT(m_fileInfo.container() != nullptr);
184  CPPUNIT_ASSERT_EQUAL("M4A "s, m_fileInfo.container()->documentType());
185  const auto tracks = m_fileInfo.tracks();
186  CPPUNIT_ASSERT_EQUAL(1_st, tracks.size());
187  for (const auto &track : tracks) {
188  switch (track->id()) {
189  case 1:
190  CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
191  CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Alac, track->format().general);
192  CPPUNIT_ASSERT_EQUAL(2008, track->creationTime().year());
193  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint16_t>(2), track->channelCount());
194  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint16_t>(16), track->bitsPerSample());
195  break;
196  default:
197  CPPUNIT_FAIL("unknown track ID");
198  }
199  }
200  const auto tags = m_fileInfo.tags();
201  switch (m_tagStatus) {
202  case TagStatus::Original:
203  CPPUNIT_ASSERT_EQUAL(1_st, tags.size());
204  CPPUNIT_ASSERT_EQUAL("Sad Song"s, tags.front()->value(KnownField::Title).toString());
205  CPPUNIT_ASSERT_EQUAL("Oasis"s, tags.front()->value(KnownField::Artist).toString());
206  CPPUNIT_ASSERT_EQUAL("Don't Go Away (Apple Lossless)"s, tags.front()->value(KnownField::Album).toString());
207  CPPUNIT_ASSERT_EQUAL("Alternative & Punk"s, tags.front()->value(KnownField::Genre).toString());
208  CPPUNIT_ASSERT_EQUAL("iTunes v7.5.0.20"s, tags.front()->value(KnownField::Encoder).toString());
209  CPPUNIT_ASSERT_EQUAL("1998"s, tags.front()->value(KnownField::Year).toString());
210  CPPUNIT_ASSERT(tags.front()->value(KnownField::Comment).isEmpty());
211  CPPUNIT_ASSERT_EQUAL(0x58f3_st, tags.front()->value(KnownField::Cover).dataSize());
212  CPPUNIT_ASSERT_EQUAL(0xFFD8FFE000104A46ul, BE::toUInt64(tags.front()->value(KnownField::Cover).dataPointer()));
213  CPPUNIT_ASSERT_EQUAL(PositionInSet(3, 4), tags.front()->value(KnownField::TrackPosition).toPositionInSet());
214  CPPUNIT_ASSERT_EQUAL(PositionInSet(1, 1), tags.front()->value(KnownField::DiskPosition).toPositionInSet());
215  break;
217  checkMp4TestMetaData();
218  break;
219  case TagStatus::Removed:
220  CPPUNIT_ASSERT_EQUAL(0_st, tracks.size());
221  }
222  CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
223 }
224 
228 void OverallTests::checkMp4Testfile5()
229 {
230  CPPUNIT_ASSERT_EQUAL(ContainerFormat::Mp4, m_fileInfo.containerFormat());
231  CPPUNIT_ASSERT(m_fileInfo.container() != nullptr);
232  CPPUNIT_ASSERT_EQUAL("mp42"s, m_fileInfo.container()->documentType());
233  const auto tracks = m_fileInfo.tracks();
234  CPPUNIT_ASSERT_EQUAL(1_st, tracks.size());
235  for (const auto &track : tracks) {
236  switch (track->id()) {
237  case 1:
238  CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
239  CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Aac, track->format().general);
240  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(SubFormats::AacMpeg4LowComplexityProfile), track->format().sub);
241  CPPUNIT_ASSERT(track->format().extension & ExtensionFormats::SpectralBandReplication);
242  CPPUNIT_ASSERT(track->format().extension & ExtensionFormats::ParametricStereo);
243  CPPUNIT_ASSERT_EQUAL(2014, track->creationTime().year());
244  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint16_t>(2), track->channelCount());
245  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(Mpeg4ChannelConfigs::FrontCenter), track->channelConfig());
246  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(Mpeg4ChannelConfigs::FrontLeftFrontRight), track->extensionChannelConfig());
247  CPPUNIT_ASSERT_EQUAL(24000u, track->samplingFrequency());
248  CPPUNIT_ASSERT_EQUAL(48000u, track->extensionSamplingFrequency());
249  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint16_t>(16), track->bitsPerSample());
250  break;
251  default:
252  CPPUNIT_FAIL("unknown track ID");
253  }
254  }
255  const auto tags = m_fileInfo.tags();
256  switch (m_tagStatus) {
257  case TagStatus::Original:
258  CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
259  break;
261  checkMp4TestMetaData();
262  break;
263  case TagStatus::Removed:
264  CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
265  }
266  CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
267 }
268 
272 void OverallTests::checkMp4Testfile6()
273 {
274  CPPUNIT_ASSERT_EQUAL(ContainerFormat::Mp4, m_fileInfo.containerFormat());
275  const auto tracks = m_fileInfo.tracks();
276  if (m_mode & Mp4TestFlags::RemoveTagOrTrack) {
277  CPPUNIT_ASSERT_EQUAL(4_st, tracks.size());
278  } else {
279  CPPUNIT_ASSERT_EQUAL(6_st, tracks.size());
280  }
281  bool track2Present = false, track5Present = false;
282  for (const auto &track : tracks) {
283  switch (track->id()) {
284  case 1:
285  CPPUNIT_ASSERT_EQUAL(MediaType::Video, track->mediaType());
286  CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Avc, track->format().general);
287  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(SubFormats::AvcHighProfile), track->format().sub);
288  CPPUNIT_ASSERT_EQUAL(4.0, track->version());
289  CPPUNIT_ASSERT_EQUAL(2013, track->creationTime().year());
290  CPPUNIT_ASSERT_EQUAL(Size(1920, 750), track->pixelSize());
291  break;
292  case 2:
293  CPPUNIT_ASSERT(track2Present = !track2Present);
294  CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
295  CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Aac, track->format().general);
296  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(SubFormats::AacMpeg4LowComplexityProfile), track->format().sub);
297  CPPUNIT_ASSERT(!(track->format().extension & ExtensionFormats::SpectralBandReplication));
298  CPPUNIT_ASSERT(!(track->format().extension & ExtensionFormats::ParametricStereo));
299  CPPUNIT_ASSERT_EQUAL("ger"s, track->language());
300  CPPUNIT_ASSERT_EQUAL("test"s, track->name());
301  CPPUNIT_ASSERT_EQUAL(2013, track->creationTime().year());
302  CPPUNIT_ASSERT_EQUAL(48000u, track->samplingFrequency());
303  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(Mpeg4ChannelConfigs::FrontLeftFrontRight), track->channelConfig());
304  break;
305  case 3:
306  CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
307  CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Ac3, track->format().general);
308  CPPUNIT_ASSERT_EQUAL("eng"s, track->language());
309  CPPUNIT_ASSERT_EQUAL(2013, track->creationTime().year());
310  break;
311  case 4:
312  CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
313  CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::DtsHd, track->format().general);
314  CPPUNIT_ASSERT_EQUAL("eng"s, track->language());
315  CPPUNIT_ASSERT_EQUAL(2013, track->creationTime().year());
316  break;
317  case 5:
318  CPPUNIT_ASSERT(track5Present = !track5Present);
319  CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
320  CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Aac, track->format().general);
321  CPPUNIT_ASSERT_EQUAL(2012, track->creationTime().year());
322  CPPUNIT_ASSERT_EQUAL(44100u, track->samplingFrequency());
323  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(Mpeg4ChannelConfigs::FrontLeftFrontRight), track->channelConfig());
324  CPPUNIT_ASSERT_EQUAL("new track"s, track->name());
325  break;
326  case 6:
327  CPPUNIT_ASSERT_EQUAL(MediaType::Text, track->mediaType());
328  CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::TimedText, track->format().general);
329  CPPUNIT_ASSERT_EQUAL(2013, track->creationTime().year());
330  break;
331  default:
332  CPPUNIT_FAIL("unknown track ID");
333  }
334  }
335  if (m_mode & Mp4TestFlags::RemoveTagOrTrack) {
336  CPPUNIT_ASSERT(!track2Present);
337  CPPUNIT_ASSERT(!track5Present);
338  } else {
339  CPPUNIT_ASSERT(track2Present);
340  CPPUNIT_ASSERT(track5Present);
341  }
342 
343  CPPUNIT_ASSERT_EQUAL(0_st, m_fileInfo.tags().size());
344  CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
345 }
346 
350 void OverallTests::checkMp4Testfile7()
351 {
352  CPPUNIT_ASSERT_EQUAL(ContainerFormat::Mp4, m_fileInfo.containerFormat());
353  CPPUNIT_ASSERT(m_fileInfo.container() != nullptr);
354  CPPUNIT_ASSERT_EQUAL("nvr1"s, m_fileInfo.container()->documentType());
355  const auto tracks = m_fileInfo.tracks();
356  CPPUNIT_ASSERT_EQUAL(3_st, tracks.size());
357  for (const auto &track : tracks) {
358  switch (track->id()) {
359  case 1:
360  CPPUNIT_ASSERT_EQUAL("VideoHandle"s, track->name());
361  CPPUNIT_ASSERT_EQUAL(MediaType::Video, track->mediaType());
362  CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Avc, track->format().general);
363  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(SubFormats::AvcBaselineProfile), track->format().sub);
364  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(0), track->format().extension);
365  CPPUNIT_ASSERT_EQUAL(4.0, track->version());
366  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint16_t>(0), track->channelCount());
367  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(0), track->channelConfig());
368  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(0), track->extensionChannelConfig());
369  CPPUNIT_ASSERT_EQUAL(0u, track->samplingFrequency());
370  CPPUNIT_ASSERT_EQUAL(0u, track->extensionSamplingFrequency());
371  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint16_t>(24), track->depth());
372  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint64_t>(51), track->sampleCount());
373  CPPUNIT_ASSERT_EQUAL(1920u, track->pixelSize().width());
374  CPPUNIT_ASSERT_EQUAL(1080u, track->pixelSize().height());
375  CPPUNIT_ASSERT_EQUAL(72u, track->resolution().width());
376  CPPUNIT_ASSERT_EQUAL(72u, track->resolution().height());
377  CPPUNIT_ASSERT_EQUAL(DateTime::fromDateAndTime(2018, 7, 8, 20, 3, 52), track->creationTime());
378  CPPUNIT_ASSERT_EQUAL(DateTime::fromDateAndTime(2018, 7, 8, 20, 3, 52), track->modificationTime());
379  CPPUNIT_ASSERT_EQUAL("YUV 4:2:0"s, string(track->chromaFormat()));
380  CPPUNIT_ASSERT_EQUAL(1, track->duration().seconds());
381  break;
382  case 2:
383  CPPUNIT_ASSERT_EQUAL("SoundHandle"s, track->name());
384  CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
385  CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Aac, track->format().general);
386  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(SubFormats::AacMpeg4LowComplexityProfile), track->format().sub);
387  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(0), track->format().extension);
388  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint16_t>(2), track->channelCount());
389  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(Mpeg4ChannelConfigs::FrontLeftFrontRight), track->channelConfig());
390  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(0), track->extensionChannelConfig());
391  CPPUNIT_ASSERT_EQUAL(48000u, track->samplingFrequency());
392  CPPUNIT_ASSERT_EQUAL(0u, track->extensionSamplingFrequency());
393  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint16_t>(16), track->bitsPerSample());
394  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint64_t>(76), track->sampleCount());
395  CPPUNIT_ASSERT_EQUAL(DateTime::fromDateAndTime(2018, 7, 8, 20, 3, 52), track->creationTime());
396  CPPUNIT_ASSERT_EQUAL(DateTime::fromDateAndTime(2018, 7, 8, 20, 3, 52), track->modificationTime());
397  CPPUNIT_ASSERT_EQUAL(1, track->duration().seconds());
398  CPPUNIT_ASSERT_EQUAL(256.0, track->bitrate());
399  break;
400  case 3:
401  CPPUNIT_ASSERT_EQUAL("MetaHandler"s, track->name());
402  CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Unknown, track->format().general);
403  CPPUNIT_ASSERT_EQUAL("urim"s, track->formatId());
404  break;
405  default:
406  CPPUNIT_FAIL("unknown track ID");
407  }
408  }
409  const auto tags = m_fileInfo.tags();
410  switch (m_tagStatus) {
411  case TagStatus::Original:
412  CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
413  break;
415  checkMp4TestMetaData();
416  break;
417  case TagStatus::Removed:
418  CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
419  }
420  CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
421 }
422 
426 void OverallTests::checkMp4TestMetaData()
427 {
428  // check whether a tag is assigned
429  const auto tags = m_fileInfo.tags();
430  Mp4Tag *tag = m_fileInfo.mp4Tag();
431  CPPUNIT_ASSERT_EQUAL(1_st, tags.size());
432  CPPUNIT_ASSERT(tag != nullptr);
433 
434  // check test meta data
435  CPPUNIT_ASSERT_EQUAL(m_testTitle, tag->value(KnownField::Title));
436  CPPUNIT_ASSERT_EQUAL(m_testComment.toString(), tag->value(KnownField::Comment).toString()); // loss of description is ok
437  CPPUNIT_ASSERT_EQUAL(m_testAlbum, tag->value(KnownField::Album));
438  CPPUNIT_ASSERT_EQUAL(m_preservedMetaData.front(), tag->value(KnownField::Artist));
439  CPPUNIT_ASSERT_EQUAL(m_testPosition, tag->value(KnownField::TrackPosition));
440  CPPUNIT_ASSERT_EQUAL(m_testPosition, tag->value(KnownField::DiskPosition));
441 
442  // TODO: check more fields
443  m_preservedMetaData.pop();
444 }
445 
449 void OverallTests::checkMp4Constraints()
450 {
451  using namespace Mp4TestFlags;
452 
453  CPPUNIT_ASSERT(m_fileInfo.container());
454  if (m_mode & PaddingConstraints) {
455  if (m_mode & ForceRewring) {
456  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint64_t>(4096), m_fileInfo.paddingSize());
457  } else {
458  CPPUNIT_ASSERT(m_fileInfo.paddingSize() >= 1024);
459  CPPUNIT_ASSERT(m_fileInfo.paddingSize() <= (4096 + 1024));
460  }
461  if (!(m_mode & RemoveTagOrTrack) && (m_fileInfo.container()->documentType() != "dash")
462  && ((m_mode & ForceRewring) || (m_mode & ForceTagPos))) {
463  const ElementPosition currentTagPos = m_fileInfo.container()->determineTagPosition(m_diag);
464  if (currentTagPos == ElementPosition::Keep) {
465  CPPUNIT_ASSERT_EQUAL(m_expectedTagPos, m_fileInfo.container()->determineIndexPosition(m_diag));
466  }
467  }
468  }
469 }
470 
474 void OverallTests::setMp4TestMetaData()
475 {
476  // ensure a tag exists
477  Tag *tag = m_fileInfo.container()->createTag();
478 
479  // assign test meta data
480  tag->setValue(KnownField::Title, m_testTitle);
481  tag->setValue(KnownField::Comment, m_testComment);
482  tag->setValue(KnownField::Album, m_testAlbum);
483  m_preservedMetaData.push(tag->value(KnownField::Artist));
484  tag->setValue(KnownField::TrackPosition, m_testPosition);
485  tag->setValue(KnownField::DiskPosition, m_testPosition);
486  // TODO: set more fields
487 }
488 
496 void OverallTests::alterMp4Tracks()
497 {
498  m_additionalFileInfo.setPath(testFilePath("mtx-test-data/mp4/10-DanseMacabreOp.40.m4a"));
499  m_additionalFileInfo.reopen(true);
500  m_additionalFileInfo.parseContainerFormat(m_diag);
501  m_additionalFileInfo.parseTracks(m_diag);
502  CPPUNIT_ASSERT_EQUAL(ContainerFormat::Mp4, m_additionalFileInfo.containerFormat());
503  CPPUNIT_ASSERT_EQUAL(ContainerFormat::Mp4, m_fileInfo.containerFormat());
504  const auto &tracks = m_additionalFileInfo.tracks();
505  CPPUNIT_ASSERT_EQUAL(1_st, tracks.size());
506  CPPUNIT_ASSERT_EQUAL(TrackType::Mp4Track, tracks[0]->type());
507  auto *track = static_cast<Mp4Track *>(tracks[0]);
508  CPPUNIT_ASSERT(static_cast<Mp4Container *>(m_additionalFileInfo.container())->removeTrack(track));
509  CPPUNIT_ASSERT_EQUAL(0_st, m_additionalFileInfo.trackCount());
510  track->setName("new track");
511  auto *container = static_cast<Mp4Container *>(m_fileInfo.container());
512  CPPUNIT_ASSERT_EQUAL(5_st, container->trackCount());
513  container->addTrack(track);
514  CPPUNIT_ASSERT_EQUAL(6_st, container->trackCount());
515  auto &secondTrack = container->tracks()[1];
516  secondTrack->setLanguage("ger");
517  secondTrack->setName("test");
518 }
519 
524 {
525  cerr << endl << "MP4 parser" << endl;
526  m_fileInfo.setForceFullParse(false);
527  m_tagStatus = TagStatus::Original;
528  parseFile(testFilePath("mtx-test-data/mp4/10-DanseMacabreOp.40.m4a"), &OverallTests::checkMp4Testfile1);
529  parseFile(testFilePath("mtx-test-data/mp4/1080p-DTS-HD-7.1.mp4"), &OverallTests::checkMp4Testfile2);
530  parseFile(testFilePath("mtx-test-data/mp4/dash/dragon-age-inquisition-H1LkM6IVlm4-video.mp4"), &OverallTests::checkMp4Testfile3);
531  parseFile(testFilePath("mtx-test-data/alac/othertest-itunes.m4a"), &OverallTests::checkMp4Testfile4);
532  parseFile(testFilePath("mtx-test-data/aac/he-aacv2-ps.m4a"), &OverallTests::checkMp4Testfile5);
533  parseFile(testFilePath("mp4/android-8.1-camera-recoding.mp4"), &OverallTests::checkMp4Testfile7);
534 }
535 
541 {
542  // full parse is required to determine padding
543  m_fileInfo.setForceFullParse(true);
544 
545  // do the test under different conditions
546  for (m_mode = 0; m_mode != 0x20; ++m_mode) {
547  using namespace Mp4TestFlags;
548 
549  // setup test conditions
550 
551  m_fileInfo.setForceRewrite(m_mode & ForceRewring);
552  if (m_mode & KeepTagPos) {
553  m_fileInfo.setTagPosition(ElementPosition::Keep);
554  } else {
555  m_fileInfo.setTagPosition(m_mode & TagsBeforeData ? ElementPosition::BeforeData : ElementPosition::AfterData);
556  }
557  m_fileInfo.setIndexPosition(m_fileInfo.tagPosition());
558  m_fileInfo.setPreferredPadding(m_mode & PaddingConstraints ? 4096 : 0);
559  m_fileInfo.setMinPadding(m_mode & PaddingConstraints ? 1024 : 0);
560  m_fileInfo.setMaxPadding(m_mode & PaddingConstraints ? (4096 + 1024) : numeric_limits<size_t>::max());
561  m_fileInfo.setForceTagPosition(m_mode & ForceTagPos);
562  m_fileInfo.setForceIndexPosition(m_mode & ForceTagPos);
563 
564  // print test conditions
565  list<string> testConditions;
566  if (m_mode & ForceRewring) {
567  testConditions.emplace_back("forcing rewrite");
568  }
569  if (m_mode & KeepTagPos) {
570  if (m_mode & RemoveTagOrTrack) {
571  testConditions.emplace_back("removing tag");
572  } else {
573  testConditions.emplace_back("keeping tag position");
574  }
575  } else if (m_mode & TagsBeforeData) {
576  testConditions.emplace_back("tags before data");
577  } else {
578  testConditions.emplace_back("tags after data");
579  }
580  if (m_mode & PaddingConstraints) {
581  testConditions.emplace_back("padding constraints");
582  }
583  if (m_mode & ForceTagPos) {
584  testConditions.emplace_back("forcing tag position");
585  }
586  cerr << endl << "MP4 maker - testmode " << m_mode << ": " << joinStrings(testConditions, ", ") << endl;
587 
588  // do actual tests
589  // -> either remove tags or set test meta data
591  void (OverallTests::*modifyRoutine)(void) = (m_mode & RemoveTagOrTrack) ? &OverallTests::removeAllTags : &OverallTests::setMp4TestMetaData;
592  makeFile(workingCopyPath("mtx-test-data/mp4/10-DanseMacabreOp.40.m4a"), modifyRoutine, &OverallTests::checkMp4Testfile1);
593  makeFile(workingCopyPath("mtx-test-data/mp4/1080p-DTS-HD-7.1.mp4"), modifyRoutine, &OverallTests::checkMp4Testfile2);
594  makeFile(
595  workingCopyPath("mtx-test-data/mp4/dash/dragon-age-inquisition-H1LkM6IVlm4-video.mp4"), modifyRoutine, &OverallTests::checkMp4Testfile3);
596  makeFile(workingCopyPath("mtx-test-data/alac/othertest-itunes.m4a"), modifyRoutine, &OverallTests::checkMp4Testfile4);
597  makeFile(workingCopyPath("mtx-test-data/aac/he-aacv2-ps.m4a"), modifyRoutine, &OverallTests::checkMp4Testfile5);
598  makeFile(workingCopyPath("mp4/android-8.1-camera-recoding.mp4"), modifyRoutine, &OverallTests::checkMp4Testfile7);
599  // -> add/remove tracks
600  modifyRoutine = (m_mode & RemoveTagOrTrack) ? &OverallTests::removeSecondTrack : &OverallTests::alterMp4Tracks;
601  m_fileInfo.setTagPosition(ElementPosition::Keep);
602  makeFile(workingCopyPath("mtx-test-data/mp4/1080p-DTS-HD-7.1.mp4"), modifyRoutine, &OverallTests::checkMp4Testfile6);
603  }
604 }
TagParser::Mp4Container
Implementation of GenericContainer<MediaFileInfo, Mp4Tag, Mp4Track, Mp4Atom>.
Definition: mp4container.h:18
TagParser::Mpeg4ElementaryStreamObjectIds::Aac
@ Aac
Definition: mp4ids.h:453
TagStatus::TestMetaDataPresent
@ TestMetaDataPresent
TagParser::SubFormats::AvcHighProfile
@ AvcHighProfile
Definition: mediaformat.h:207
TagParser::Mp4TagAtomIds::Album
@ Album
Definition: mp4ids.h:86
OverallTests::testMp4Making
void testMp4Making()
Tests the MP4 maker via MediaFileInfo.
Definition: overallmp4.cpp:540
TagParser::Mp4TagAtomIds::Encoder
@ Encoder
Definition: mp4ids.h:97
TagStatus::Original
@ Original
TagParser::Mp4TagAtomIds::Cover
@ Cover
Definition: mp4ids.h:94
Mp4TestFlags
Definition: overallmp4.cpp:11
Mp4TestFlags::TagsBeforeData
@ TagsBeforeData
Definition: overallmp4.cpp:15
TagParser::Tag
The Tag class is used to store, read and write tag information.
Definition: tag.h:98
TagParser::ExtensionFormats::SpectralBandReplication
@ SpectralBandReplication
Definition: mediaformat.h:242
TagParser::Mp4TagAtomIds::TrackPosition
@ TrackPosition
Definition: mp4ids.h:116
Mp4TestFlags::KeepTagPos
@ KeepTagPos
Definition: overallmp4.cpp:14
Mp4TestFlags::TestFlag
TestFlag
Definition: overallmp4.cpp:12
OverallTests::testMp4Parsing
void testMp4Parsing()
Tests the MP4 parser via MediaFileInfo.
Definition: overallmp4.cpp:523
TagParser::Mpeg4ElementaryStreamObjectIds::Avc
@ Avc
Definition: mp4ids.h:449
TagParser::FourccIds::Ac3
@ Ac3
Definition: mp4ids.h:146
overall.h
TagParser::SubFormats::AacMpeg4LowComplexityProfile
@ AacMpeg4LowComplexityProfile
Definition: mediaformat.h:119
TagParser::MatroskaIds::Title
@ Title
Definition: matroskaid.h:54
Mp4TestFlags::ForceTagPos
@ ForceTagPos
Definition: overallmp4.cpp:18
TagParser::Mpeg4ChannelConfigs::FrontCenter
@ FrontCenter
Definition: mp4ids.h:615
TagParser::Mp4TagAtomIds::Year
@ Year
Definition: mp4ids.h:122
TagParser::Mp4Tag::value
const TagValue & value(KnownField value) const override
Returns the value of the specified field.
Definition: mp4tag.cpp:62
TagParser::Tag::value
virtual const TagValue & value(KnownField field) const =0
Returns the value of the specified field.
CppUtilities
Definition: abstractcontainer.h:15
TagParser::Size
The Size class defines the size of a two-dimensional object using integer point precision.
Definition: size.h:16
TagParser::Mp4TagAtomIds::Genre
@ Genre
Definition: mp4ids.h:101
TagParser::SubFormats::AvcBaselineProfile
@ AvcBaselineProfile
Definition: mediaformat.h:202
TagParser::Mp4Track
Implementation of TagParser::AbstractTrack for the MP4 container.
Definition: mp4track.h:118
Mp4TestFlags::PaddingConstraints
@ PaddingConstraints
Definition: overallmp4.cpp:17
TagStatus::Removed
@ Removed
TagParser::ElementPosition
ElementPosition
Definition: settings.h:13
TagParser::Mp4Tag
Implementation of TagParser::Tag for the MP4 container.
Definition: mp4tag.h:97
TagParser::FourccIds::Alac
@ Alac
Definition: mp4ids.h:150
TagParser::TagValue::toString
std::string toString(TagTextEncoding encoding=TagTextEncoding::Unspecified) const
Converts the value of the current TagValue object to its equivalent std::string representation.
Definition: tagvalue.h:407
TagParser::GenericContainer::removeTrack
bool removeTrack(AbstractTrack *track) override
Removes the specified track to the container.
Definition: genericcontainer.h:336
Mp4TestFlags::ForceRewring
@ ForceRewring
Definition: overallmp4.cpp:13
TagParser::PositionInSet
The PositionInSet class describes the position of an element in a set which consists of a certain num...
Definition: positioninset.h:21
TagParser::MatroskaTrackType::Video
@ Video
Definition: matroskaid.h:403
OverallTests
The OverallTests class tests reading and writing tags and parsing technical information for all suppo...
Definition: overall.h:40
TagParser::Mp4TagAtomIds::Artist
@ Artist
Definition: mp4ids.h:88
Mp4TestFlags::RemoveTagOrTrack
@ RemoveTagOrTrack
Definition: overallmp4.cpp:16
helper.h
TagParser::Mp4TagAtomIds::DiskPosition
@ DiskPosition
Definition: mp4ids.h:96
TagParser::Mp4TagAtomIds::Comment
@ Comment
Definition: mp4ids.h:91
TagParser::SubFormats::AvcMainProfile
@ AvcMainProfile
Definition: mediaformat.h:203
TagParser::Mpeg4ChannelConfigs::FrontLeftFrontRight
@ FrontLeftFrontRight
Definition: mp4ids.h:616
TagParser::Tag::setValue
virtual bool setValue(KnownField field, const TagValue &value)=0
Assigns the given value to the specified field.
TagParser::ExtensionFormats::ParametricStereo
@ ParametricStereo
Definition: mediaformat.h:242
TagParser::MatroskaTrackType::Audio
@ Audio
Definition: matroskaid.h:403
TagParser::Mp4
@ Mp4
Definition: signature.cpp:53