Tag Parser 12.1.0
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
Loading...
Searching...
No Matches
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
9using namespace CppUtilities;
10
21
25void 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;
58 CPPUNIT_ASSERT_EQUAL(0_st, tracks.size());
59 }
60 CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
61}
62
66void 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(Locale("eng"sv, LocaleFormat::ISO_639_2_T), track->locale());
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(Locale("eng"sv, LocaleFormat::ISO_639_2_T), track->locale());
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(Locale("eng"sv, LocaleFormat::ISO_639_2_T), track->locale());
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) {
116 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
117 break;
119 checkMp4TestMetaData();
120 break;
122 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
123 }
124 CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
125}
126
130void 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) {
155 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
156 break;
158 checkMp4TestMetaData();
159 break;
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
180void 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) {
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::RecordDate).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::toInt<std::uint64_t>(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;
220 CPPUNIT_ASSERT_EQUAL(0_st, tracks.size());
221 }
222 CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
223}
224
228void 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) {
258 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
259 break;
261 checkMp4TestMetaData();
262 break;
264 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
265 }
266 CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
267}
268
272void 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(Locale("ger"sv, LocaleFormat::ISO_639_2_T), track->locale());
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(Locale("eng"sv, LocaleFormat::ISO_639_2_T), track->locale());
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(Locale("eng"sv, LocaleFormat::ISO_639_2_T), track->locale());
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
350void 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) {
412 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
413 break;
415 checkMp4TestMetaData();
416 break;
418 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
419 }
420 CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
421}
422
426void 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
449void 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
474void 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
496void 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, m_progress);
501 m_additionalFileInfo.parseTracks(m_diag, m_progress);
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->setLocale(Locale("ger"sv, LocaleFormat::ISO_639_2_T));
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
590 m_tagStatus = (m_mode & RemoveTagOrTrack) ? TagStatus::Removed : TagStatus::TestMetaDataPresent;
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}
The OverallTests class tests reading and writing tags and parsing technical information for all suppo...
Definition overall.h:40
void testMp4Making()
Tests the MP4 maker via MediaFileInfo.
void testMp4Parsing()
Tests the MP4 parser via MediaFileInfo.
virtual ElementPosition determineTagPosition(Diagnostics &diag) const
Determines the position of the tags inside the file.
virtual ElementPosition determineIndexPosition(Diagnostics &diag) const
Determines the position of the index.
const std::string & documentType() const
Returns a string that describes the document type if available; otherwise returns an empty string.
virtual Tag * createTag(const TagTarget &target=TagTarget())
Creates and returns a tag for the specified target.
void reopen(bool readOnly=false)
Opens a std::fstream for the current file.
void setPath(std::string_view path)
Sets the current file.
DiagLevel level() const
Returns the worst diag level present in the container.
bool removeTrack(AbstractTrack *track) override
Removes the specified track to the container.
std::uint64_t paddingSize() const
Returns the padding size.
std::vector< AbstractTrack * > tracks() const
Returns the tracks for the current file.
void setForceRewrite(bool forceRewrite)
Sets whether forcing rewriting (when applying changes) is enabled.
void setMaxPadding(std::size_t maxPadding)
Sets the maximum padding to be written before the data blocks when applying changes.
std::size_t trackCount() const
Returns the number of tracks that could be parsed.
void setMinPadding(std::size_t minPadding)
Sets the minimum padding to be written before the data blocks when applying changes.
void parseTracks(Diagnostics &diag, AbortableProgressFeedback &progress)
Parses the tracks of the current file.
void parseContainerFormat(Diagnostics &diag, AbortableProgressFeedback &progress)
Parses the container format of the current file.
void setForceTagPosition(bool forceTagPosition)
Sets whether tagPosition() is forced.
void setForceFullParse(bool forceFullParse)
Sets whether forcing a full parse is enabled.
void tags(std::vector< Tag * > &tags) const
Stores all tags assigned to the current file in the specified vector.
void setTagPosition(ElementPosition tagPosition)
Sets the position (in the output file) where the tag information is written when applying changes.
ElementPosition tagPosition() const
Returns the position (in the output file) where the tag information is written when applying changes.
AbstractContainer * container() const
Returns the container for the current file.
ContainerFormat containerFormat() const
Returns the container format of the current file.
void setIndexPosition(ElementPosition indexPosition)
Sets the position (in the output file) where the index is written when applying changes.
void setPreferredPadding(std::size_t preferredPadding)
Sets the padding to be written before the data block when applying changes and the file needs to be r...
void setForceIndexPosition(bool forceTagPosition)
Sets whether indexPosition() is forced.
Mp4Tag * mp4Tag() const
Returns a pointer to the assigned MP4 tag or nullptr if none is assigned.
Implementation of GenericContainer<MediaFileInfo, Mp4Tag, Mp4Track, Mp4Atom>.
Implementation of TagParser::Tag for the MP4 container.
Definition mp4tag.h:97
const TagValue & value(KnownField value) const override
Returns the value of the specified field.
Definition mp4tag.cpp:59
Implementation of TagParser::AbstractTrack for the MP4 container.
Definition mp4track.h:119
The PositionInSet class describes the position of an element in a set which consists of a certain num...
The Size class defines the size of a two-dimensional object using integer point precision.
Definition size.h:17
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:450
The Tag class is used to store, read and write tag information.
Definition tag.h:166
virtual bool setValue(KnownField field, const TagValue &value)=0
Assigns the given value to the specified field.
virtual const TagValue & value(KnownField field) const =0
Returns the value of the specified field.
ElementPosition
Definition settings.h:13
@ TestMetaDataPresent
The Locale struct specifies a language and/or a country using one or more LocaleDetail objects.