4 #include "../abstracttrack.h"
5 #include "../mp4/mp4container.h"
6 #include "../mp4/mp4ids.h"
7 #include "../mp4/mp4tag.h"
25 void OverallTests::checkMp4Testfile1()
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()) {
35 CPPUNIT_ASSERT_EQUAL(2012, track->creationTime().year());
36 CPPUNIT_ASSERT_EQUAL(44100u, track->samplingFrequency());
40 CPPUNIT_FAIL(
"unknown track ID");
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());
51 "qaac 1.32, CoreAudioToolbox 7.9.7.3, AAC-LC Encoder, TVBR q63, Quality 96"s, tags.front()->value(
KnownField::Encoder).toString());
55 checkMp4TestMetaData();
58 CPPUNIT_ASSERT_EQUAL(0_st, tracks.size());
60 CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
66 void OverallTests::checkMp4Testfile2()
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()) {
77 CPPUNIT_ASSERT_EQUAL(4.0, track->version());
78 CPPUNIT_ASSERT_EQUAL(2013, track->creationTime().year());
79 CPPUNIT_ASSERT(track->pixelSize() ==
Size(1920, 750));
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());
95 CPPUNIT_ASSERT_EQUAL(
Locale(
"eng"sv, LocaleFormat::ISO_639_2_T), track->locale());
96 CPPUNIT_ASSERT_EQUAL(2013, track->creationTime().year());
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());
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());
110 CPPUNIT_FAIL(
"unknown track ID");
113 const auto tags = m_fileInfo.tags();
114 switch (m_tagStatus) {
116 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
119 checkMp4TestMetaData();
122 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
124 CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
130 void OverallTests::checkMp4Testfile3()
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()) {
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()));
149 CPPUNIT_FAIL(
"unknown track ID");
152 const auto tags = m_fileInfo.tags();
153 switch (m_tagStatus) {
155 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
158 checkMp4TestMetaData();
161 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
164 for (
const auto &msg : m_diag) {
165 if (msg.level() != DiagLevel::Warning) {
169 CPPUNIT_FAIL(
"No warnings expected when putting tags before data.");
171 CPPUNIT_ASSERT_EQUAL(
"Sorry, but putting index/tags at the end is not possible when dealing with DASH files."s, msg.message());
174 CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Warning);
180 void OverallTests::checkMp4Testfile4()
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()) {
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());
197 CPPUNIT_FAIL(
"unknown track ID");
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());
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());
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()));
217 checkMp4TestMetaData();
220 CPPUNIT_ASSERT_EQUAL(0_st, tracks.size());
222 CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
228 void OverallTests::checkMp4Testfile5()
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()) {
243 CPPUNIT_ASSERT_EQUAL(2014, track->creationTime().year());
244 CPPUNIT_ASSERT_EQUAL(
static_cast<std::uint16_t
>(2), track->channelCount());
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());
252 CPPUNIT_FAIL(
"unknown track ID");
255 const auto tags = m_fileInfo.tags();
256 switch (m_tagStatus) {
258 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
261 checkMp4TestMetaData();
264 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
266 CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
272 void OverallTests::checkMp4Testfile6()
275 const auto tracks = m_fileInfo.tracks();
277 CPPUNIT_ASSERT_EQUAL(4_st, tracks.size());
279 CPPUNIT_ASSERT_EQUAL(6_st, tracks.size());
281 bool track2Present =
false, track5Present =
false;
282 for (
const auto &track : tracks) {
283 switch (track->id()) {
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());
293 CPPUNIT_ASSERT(track2Present = !track2Present);
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());
308 CPPUNIT_ASSERT_EQUAL(
Locale(
"eng"sv, LocaleFormat::ISO_639_2_T), track->locale());
309 CPPUNIT_ASSERT_EQUAL(2013, track->creationTime().year());
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());
318 CPPUNIT_ASSERT(track5Present = !track5Present);
321 CPPUNIT_ASSERT_EQUAL(2012, track->creationTime().year());
322 CPPUNIT_ASSERT_EQUAL(44100u, track->samplingFrequency());
324 CPPUNIT_ASSERT_EQUAL(
"new track"s, track->name());
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());
332 CPPUNIT_FAIL(
"unknown track ID");
336 CPPUNIT_ASSERT(!track2Present);
337 CPPUNIT_ASSERT(!track5Present);
339 CPPUNIT_ASSERT(track2Present);
340 CPPUNIT_ASSERT(track5Present);
343 CPPUNIT_ASSERT_EQUAL(0_st, m_fileInfo.tags().size());
344 CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
350 void OverallTests::checkMp4Testfile7()
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()) {
360 CPPUNIT_ASSERT_EQUAL(
"VideoHandle"s, track->name());
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());
383 CPPUNIT_ASSERT_EQUAL(
"SoundHandle"s, track->name());
387 CPPUNIT_ASSERT_EQUAL(
static_cast<unsigned char>(0), track->format().extension);
388 CPPUNIT_ASSERT_EQUAL(
static_cast<std::uint16_t
>(2), track->channelCount());
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());
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());
406 CPPUNIT_FAIL(
"unknown track ID");
409 const auto tags = m_fileInfo.tags();
410 switch (m_tagStatus) {
412 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
415 checkMp4TestMetaData();
418 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
420 CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
426 void OverallTests::checkMp4TestMetaData()
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);
443 m_preservedMetaData.pop();
449 void OverallTests::checkMp4Constraints()
453 CPPUNIT_ASSERT(m_fileInfo.container());
456 CPPUNIT_ASSERT_EQUAL(
static_cast<std::uint64_t
>(4096), m_fileInfo.paddingSize());
458 CPPUNIT_ASSERT(m_fileInfo.paddingSize() >= 1024);
459 CPPUNIT_ASSERT(m_fileInfo.paddingSize() <= (4096 + 1024));
461 if (!(m_mode &
RemoveTagOrTrack) && (m_fileInfo.container()->documentType() !=
"dash")
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));
474 void OverallTests::setMp4TestMetaData()
477 Tag *tag = m_fileInfo.container()->createTag();
496 void OverallTests::alterMp4Tracks()
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);
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]);
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");
525 cerr << endl <<
"MP4 parser" << endl;
526 m_fileInfo.setForceFullParse(
false);
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);
543 m_fileInfo.setForceFullParse(
true);
546 for (m_mode = 0; m_mode != 0x20; ++m_mode) {
553 m_fileInfo.setTagPosition(ElementPosition::Keep);
555 m_fileInfo.setTagPosition(m_mode &
TagsBeforeData ? ElementPosition::BeforeData : ElementPosition::AfterData);
557 m_fileInfo.setIndexPosition(m_fileInfo.tagPosition());
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);
565 list<string> testConditions;
567 testConditions.emplace_back(
"forcing rewrite");
571 testConditions.emplace_back(
"removing tag");
573 testConditions.emplace_back(
"keeping tag position");
576 testConditions.emplace_back(
"tags before data");
578 testConditions.emplace_back(
"tags after data");
581 testConditions.emplace_back(
"padding constraints");
584 testConditions.emplace_back(
"forcing tag position");
586 cerr << endl <<
"MP4 maker - testmode " << m_mode <<
": " << joinStrings(testConditions,
", ") << endl;
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);
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);
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);
The OverallTests class tests reading and writing tags and parsing technical information for all suppo...
void testMp4Making()
Tests the MP4 maker via MediaFileInfo.
void testMp4Parsing()
Tests the MP4 parser via MediaFileInfo.
bool removeTrack(AbstractTrack *track) override
Removes the specified track to the container.
Implementation of GenericContainer<MediaFileInfo, Mp4Tag, Mp4Track, Mp4Atom>.
Implementation of TagParser::Tag for the MP4 container.
const TagValue & value(KnownField value) const override
Returns the value of the specified field.
Implementation of TagParser::AbstractTrack for the MP4 container.
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.
std::string toString(TagTextEncoding encoding=TagTextEncoding::Unspecified) const
Converts the value of the current TagValue object to its equivalent std::string representation.
The Tag class is used to store, read and write tag information.
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.
The Locale struct specifies a language and/or a country using one or more LocaleDetail objects.