tagparser/tests/overallmp4.cpp
Martchus 6b469f1c26 Add Locale class to deal with differently specified languages/countries
Different media/tag formats specify languages and countries
differently. This change introduces a Locale class to keep track
of the format being used. So far there are no automatic conversions
implemented so it is entirely up to the user to pass valid values using
a format which matches the one required by the media/tag format.

This change also adds support for Matroska's IETF elements so at least the
raw value can be read, written and is preserved.
2020-12-16 17:48:08 +01:00

605 lines
28 KiB
C++

#include "./helper.h"
#include "./overall.h"
#include "../abstracttrack.h"
#include "../mp4/mp4container.h"
#include "../mp4/mp4ids.h"
#include "../mp4/mp4tag.h"
using namespace CppUtilities;
namespace Mp4TestFlags {
enum TestFlag {
ForceRewring = 0x1,
KeepTagPos = 0x2,
TagsBeforeData = 0x10,
RemoveTagOrTrack = KeepTagPos & TagsBeforeData,
PaddingConstraints = 0x4,
ForceTagPos = 0x8,
};
}
/*!
* \brief Checks "mtx-test-data/mp4/10-DanseMacabreOp.40.m4a"
*/
void OverallTests::checkMp4Testfile1()
{
CPPUNIT_ASSERT_EQUAL(ContainerFormat::Mp4, m_fileInfo.containerFormat());
const auto tracks = m_fileInfo.tracks();
CPPUNIT_ASSERT_EQUAL(1_st, tracks.size());
for (const auto &track : tracks) {
switch (track->id()) {
case 1:
CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Aac, track->format().general);
CPPUNIT_ASSERT_EQUAL(2012, track->creationTime().year());
CPPUNIT_ASSERT_EQUAL(44100u, track->samplingFrequency());
CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(Mpeg4ChannelConfigs::FrontLeftFrontRight), track->channelConfig());
break;
default:
CPPUNIT_FAIL("unknown track ID");
}
}
const auto tags = m_fileInfo.tags();
switch (m_tagStatus) {
case TagStatus::Original:
CPPUNIT_ASSERT_EQUAL(1_st, tags.size());
CPPUNIT_ASSERT_EQUAL("Danse Macabre, Op.40"s, tags.front()->value(KnownField::Title).toString());
CPPUNIT_ASSERT_EQUAL("Saint-Saëns"s, tags.front()->value(KnownField::Artist).toString());
CPPUNIT_ASSERT_EQUAL("Classical"s, tags.front()->value(KnownField::Genre).toString());
CPPUNIT_ASSERT_EQUAL(
"qaac 1.32, CoreAudioToolbox 7.9.7.3, AAC-LC Encoder, TVBR q63, Quality 96"s, tags.front()->value(KnownField::Encoder).toString());
CPPUNIT_ASSERT_EQUAL(10, tags.front()->value(KnownField::TrackPosition).toPositionInSet().position());
break;
case TagStatus::TestMetaDataPresent:
checkMp4TestMetaData();
break;
case TagStatus::Removed:
CPPUNIT_ASSERT_EQUAL(0_st, tracks.size());
}
CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
}
/*!
* \brief Checks "mtx-test-data/mp4/1080p-DTS-HD-7.1.mp4"
*/
void OverallTests::checkMp4Testfile2()
{
CPPUNIT_ASSERT_EQUAL(ContainerFormat::Mp4, m_fileInfo.containerFormat());
const auto tracks = m_fileInfo.tracks();
CPPUNIT_ASSERT_EQUAL(5_st, tracks.size());
for (const auto &track : tracks) {
switch (track->id()) {
case 1:
CPPUNIT_ASSERT_EQUAL(MediaType::Video, track->mediaType());
CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Avc, track->format().general);
CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(SubFormats::AvcHighProfile), track->format().sub);
CPPUNIT_ASSERT_EQUAL(4.0, track->version());
CPPUNIT_ASSERT_EQUAL(2013, track->creationTime().year());
CPPUNIT_ASSERT(track->pixelSize() == Size(1920, 750));
break;
case 2:
CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Aac, track->format().general);
CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(SubFormats::AacMpeg4LowComplexityProfile), track->format().sub);
CPPUNIT_ASSERT(!(track->format().extension & ExtensionFormats::SpectralBandReplication));
CPPUNIT_ASSERT(!(track->format().extension & ExtensionFormats::ParametricStereo));
CPPUNIT_ASSERT_EQUAL(Locale("eng"sv, LocaleFormat::ISO_639_2_T), track->locale());
CPPUNIT_ASSERT_EQUAL(2013, track->creationTime().year());
CPPUNIT_ASSERT_EQUAL(48000u, track->samplingFrequency());
CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(Mpeg4ChannelConfigs::FrontLeftFrontRight), track->channelConfig());
break;
case 3:
CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Ac3, track->format().general);
CPPUNIT_ASSERT_EQUAL(Locale("eng"sv, LocaleFormat::ISO_639_2_T), track->locale());
CPPUNIT_ASSERT_EQUAL(2013, track->creationTime().year());
break;
case 4:
CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::DtsHd, track->format().general);
CPPUNIT_ASSERT_EQUAL(Locale("eng"sv, LocaleFormat::ISO_639_2_T), track->locale());
CPPUNIT_ASSERT_EQUAL(2013, track->creationTime().year());
break;
case 6:
CPPUNIT_ASSERT_EQUAL(MediaType::Text, track->mediaType());
CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::TimedText, track->format().general);
CPPUNIT_ASSERT_EQUAL(2013, track->creationTime().year());
break;
default:
CPPUNIT_FAIL("unknown track ID");
}
}
const auto tags = m_fileInfo.tags();
switch (m_tagStatus) {
case TagStatus::Original:
CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
break;
case TagStatus::TestMetaDataPresent:
checkMp4TestMetaData();
break;
case TagStatus::Removed:
CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
}
CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
}
/*!
* \brief Checks "mtx-test-data/mp4/dash/dragon-age-inquisition-H1LkM6IVlm4-video.mp4"
*/
void OverallTests::checkMp4Testfile3()
{
CPPUNIT_ASSERT_EQUAL(ContainerFormat::Mp4, m_fileInfo.containerFormat());
CPPUNIT_ASSERT(m_fileInfo.container() != nullptr);
CPPUNIT_ASSERT_EQUAL("dash"s, m_fileInfo.container()->documentType());
const auto tracks = m_fileInfo.tracks();
CPPUNIT_ASSERT_EQUAL(1_st, tracks.size());
for (const auto &track : tracks) {
switch (track->id()) {
case 1:
CPPUNIT_ASSERT_EQUAL(MediaType::Video, track->mediaType());
CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Avc, track->format().general);
CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(SubFormats::AvcMainProfile), track->format().sub);
CPPUNIT_ASSERT_EQUAL(3.1, track->version());
CPPUNIT_ASSERT_EQUAL(2014, track->creationTime().year());
CPPUNIT_ASSERT_EQUAL(Size(854, 480), track->pixelSize());
CPPUNIT_ASSERT_EQUAL("YUV 4:2:0"s, string(track->chromaFormat()));
break;
default:
CPPUNIT_FAIL("unknown track ID");
}
}
const auto tags = m_fileInfo.tags();
switch (m_tagStatus) {
case TagStatus::Original:
CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
break;
case TagStatus::TestMetaDataPresent:
checkMp4TestMetaData();
break;
case TagStatus::Removed:
CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
}
for (const auto &msg : m_diag) {
if (msg.level() != DiagLevel::Warning) {
continue;
}
if (m_mode & Mp4TestFlags::TagsBeforeData) {
CPPUNIT_FAIL("No warnings expected when putting tags before data.");
} else {
CPPUNIT_ASSERT_EQUAL("Sorry, but putting index/tags at the end is not possible when dealing with DASH files."s, msg.message());
}
}
CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Warning);
}
/*!
* \brief Checks "mtx-test-data/mp4/alac/othertest-itunes.m4a"
*/
void OverallTests::checkMp4Testfile4()
{
CPPUNIT_ASSERT_EQUAL(ContainerFormat::Mp4, m_fileInfo.containerFormat());
CPPUNIT_ASSERT(m_fileInfo.container() != nullptr);
CPPUNIT_ASSERT_EQUAL("M4A "s, m_fileInfo.container()->documentType());
const auto tracks = m_fileInfo.tracks();
CPPUNIT_ASSERT_EQUAL(1_st, tracks.size());
for (const auto &track : tracks) {
switch (track->id()) {
case 1:
CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Alac, track->format().general);
CPPUNIT_ASSERT_EQUAL(2008, track->creationTime().year());
CPPUNIT_ASSERT_EQUAL(static_cast<std::uint16_t>(2), track->channelCount());
CPPUNIT_ASSERT_EQUAL(static_cast<std::uint16_t>(16), track->bitsPerSample());
break;
default:
CPPUNIT_FAIL("unknown track ID");
}
}
const auto tags = m_fileInfo.tags();
switch (m_tagStatus) {
case TagStatus::Original:
CPPUNIT_ASSERT_EQUAL(1_st, tags.size());
CPPUNIT_ASSERT_EQUAL("Sad Song"s, tags.front()->value(KnownField::Title).toString());
CPPUNIT_ASSERT_EQUAL("Oasis"s, tags.front()->value(KnownField::Artist).toString());
CPPUNIT_ASSERT_EQUAL("Don't Go Away (Apple Lossless)"s, tags.front()->value(KnownField::Album).toString());
CPPUNIT_ASSERT_EQUAL("Alternative & Punk"s, tags.front()->value(KnownField::Genre).toString());
CPPUNIT_ASSERT_EQUAL("iTunes v7.5.0.20"s, tags.front()->value(KnownField::Encoder).toString());
CPPUNIT_ASSERT_EQUAL("1998"s, tags.front()->value(KnownField::Year).toString());
CPPUNIT_ASSERT(tags.front()->value(KnownField::Comment).isEmpty());
CPPUNIT_ASSERT_EQUAL(0x58f3_st, tags.front()->value(KnownField::Cover).dataSize());
CPPUNIT_ASSERT_EQUAL(0xFFD8FFE000104A46ul, BE::toUInt64(tags.front()->value(KnownField::Cover).dataPointer()));
CPPUNIT_ASSERT_EQUAL(PositionInSet(3, 4), tags.front()->value(KnownField::TrackPosition).toPositionInSet());
CPPUNIT_ASSERT_EQUAL(PositionInSet(1, 1), tags.front()->value(KnownField::DiskPosition).toPositionInSet());
break;
case TagStatus::TestMetaDataPresent:
checkMp4TestMetaData();
break;
case TagStatus::Removed:
CPPUNIT_ASSERT_EQUAL(0_st, tracks.size());
}
CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
}
/*!
* \brief Checks "mtx-test-data/aac/he-aacv2-ps.m4a"
*/
void OverallTests::checkMp4Testfile5()
{
CPPUNIT_ASSERT_EQUAL(ContainerFormat::Mp4, m_fileInfo.containerFormat());
CPPUNIT_ASSERT(m_fileInfo.container() != nullptr);
CPPUNIT_ASSERT_EQUAL("mp42"s, m_fileInfo.container()->documentType());
const auto tracks = m_fileInfo.tracks();
CPPUNIT_ASSERT_EQUAL(1_st, tracks.size());
for (const auto &track : tracks) {
switch (track->id()) {
case 1:
CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Aac, track->format().general);
CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(SubFormats::AacMpeg4LowComplexityProfile), track->format().sub);
CPPUNIT_ASSERT(track->format().extension & ExtensionFormats::SpectralBandReplication);
CPPUNIT_ASSERT(track->format().extension & ExtensionFormats::ParametricStereo);
CPPUNIT_ASSERT_EQUAL(2014, track->creationTime().year());
CPPUNIT_ASSERT_EQUAL(static_cast<std::uint16_t>(2), track->channelCount());
CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(Mpeg4ChannelConfigs::FrontCenter), track->channelConfig());
CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(Mpeg4ChannelConfigs::FrontLeftFrontRight), track->extensionChannelConfig());
CPPUNIT_ASSERT_EQUAL(24000u, track->samplingFrequency());
CPPUNIT_ASSERT_EQUAL(48000u, track->extensionSamplingFrequency());
CPPUNIT_ASSERT_EQUAL(static_cast<std::uint16_t>(16), track->bitsPerSample());
break;
default:
CPPUNIT_FAIL("unknown track ID");
}
}
const auto tags = m_fileInfo.tags();
switch (m_tagStatus) {
case TagStatus::Original:
CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
break;
case TagStatus::TestMetaDataPresent:
checkMp4TestMetaData();
break;
case TagStatus::Removed:
CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
}
CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
}
/*!
* \brief Checks "mtx-test-data/mp4/1080p-DTS-HD-7.1.mp4" after adding/removing track.
*/
void OverallTests::checkMp4Testfile6()
{
CPPUNIT_ASSERT_EQUAL(ContainerFormat::Mp4, m_fileInfo.containerFormat());
const auto tracks = m_fileInfo.tracks();
if (m_mode & Mp4TestFlags::RemoveTagOrTrack) {
CPPUNIT_ASSERT_EQUAL(4_st, tracks.size());
} else {
CPPUNIT_ASSERT_EQUAL(6_st, tracks.size());
}
bool track2Present = false, track5Present = false;
for (const auto &track : tracks) {
switch (track->id()) {
case 1:
CPPUNIT_ASSERT_EQUAL(MediaType::Video, track->mediaType());
CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Avc, track->format().general);
CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(SubFormats::AvcHighProfile), track->format().sub);
CPPUNIT_ASSERT_EQUAL(4.0, track->version());
CPPUNIT_ASSERT_EQUAL(2013, track->creationTime().year());
CPPUNIT_ASSERT_EQUAL(Size(1920, 750), track->pixelSize());
break;
case 2:
CPPUNIT_ASSERT(track2Present = !track2Present);
CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Aac, track->format().general);
CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(SubFormats::AacMpeg4LowComplexityProfile), track->format().sub);
CPPUNIT_ASSERT(!(track->format().extension & ExtensionFormats::SpectralBandReplication));
CPPUNIT_ASSERT(!(track->format().extension & ExtensionFormats::ParametricStereo));
CPPUNIT_ASSERT_EQUAL(Locale("ger"sv, LocaleFormat::ISO_639_2_T), track->locale());
CPPUNIT_ASSERT_EQUAL("test"s, track->name());
CPPUNIT_ASSERT_EQUAL(2013, track->creationTime().year());
CPPUNIT_ASSERT_EQUAL(48000u, track->samplingFrequency());
CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(Mpeg4ChannelConfigs::FrontLeftFrontRight), track->channelConfig());
break;
case 3:
CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Ac3, track->format().general);
CPPUNIT_ASSERT_EQUAL(Locale("eng"sv, LocaleFormat::ISO_639_2_T), track->locale());
CPPUNIT_ASSERT_EQUAL(2013, track->creationTime().year());
break;
case 4:
CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::DtsHd, track->format().general);
CPPUNIT_ASSERT_EQUAL(Locale("eng"sv, LocaleFormat::ISO_639_2_T), track->locale());
CPPUNIT_ASSERT_EQUAL(2013, track->creationTime().year());
break;
case 5:
CPPUNIT_ASSERT(track5Present = !track5Present);
CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Aac, track->format().general);
CPPUNIT_ASSERT_EQUAL(2012, track->creationTime().year());
CPPUNIT_ASSERT_EQUAL(44100u, track->samplingFrequency());
CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(Mpeg4ChannelConfigs::FrontLeftFrontRight), track->channelConfig());
CPPUNIT_ASSERT_EQUAL("new track"s, track->name());
break;
case 6:
CPPUNIT_ASSERT_EQUAL(MediaType::Text, track->mediaType());
CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::TimedText, track->format().general);
CPPUNIT_ASSERT_EQUAL(2013, track->creationTime().year());
break;
default:
CPPUNIT_FAIL("unknown track ID");
}
}
if (m_mode & Mp4TestFlags::RemoveTagOrTrack) {
CPPUNIT_ASSERT(!track2Present);
CPPUNIT_ASSERT(!track5Present);
} else {
CPPUNIT_ASSERT(track2Present);
CPPUNIT_ASSERT(track5Present);
}
CPPUNIT_ASSERT_EQUAL(0_st, m_fileInfo.tags().size());
CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
}
/*!
* \brief Checks "mp4/android-8.1-camera-recoding.mp4".
*/
void OverallTests::checkMp4Testfile7()
{
CPPUNIT_ASSERT_EQUAL(ContainerFormat::Mp4, m_fileInfo.containerFormat());
CPPUNIT_ASSERT(m_fileInfo.container() != nullptr);
CPPUNIT_ASSERT_EQUAL("nvr1"s, m_fileInfo.container()->documentType());
const auto tracks = m_fileInfo.tracks();
CPPUNIT_ASSERT_EQUAL(3_st, tracks.size());
for (const auto &track : tracks) {
switch (track->id()) {
case 1:
CPPUNIT_ASSERT_EQUAL("VideoHandle"s, track->name());
CPPUNIT_ASSERT_EQUAL(MediaType::Video, track->mediaType());
CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Avc, track->format().general);
CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(SubFormats::AvcBaselineProfile), track->format().sub);
CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(0), track->format().extension);
CPPUNIT_ASSERT_EQUAL(4.0, track->version());
CPPUNIT_ASSERT_EQUAL(static_cast<std::uint16_t>(0), track->channelCount());
CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(0), track->channelConfig());
CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(0), track->extensionChannelConfig());
CPPUNIT_ASSERT_EQUAL(0u, track->samplingFrequency());
CPPUNIT_ASSERT_EQUAL(0u, track->extensionSamplingFrequency());
CPPUNIT_ASSERT_EQUAL(static_cast<std::uint16_t>(24), track->depth());
CPPUNIT_ASSERT_EQUAL(static_cast<std::uint64_t>(51), track->sampleCount());
CPPUNIT_ASSERT_EQUAL(1920u, track->pixelSize().width());
CPPUNIT_ASSERT_EQUAL(1080u, track->pixelSize().height());
CPPUNIT_ASSERT_EQUAL(72u, track->resolution().width());
CPPUNIT_ASSERT_EQUAL(72u, track->resolution().height());
CPPUNIT_ASSERT_EQUAL(DateTime::fromDateAndTime(2018, 7, 8, 20, 3, 52), track->creationTime());
CPPUNIT_ASSERT_EQUAL(DateTime::fromDateAndTime(2018, 7, 8, 20, 3, 52), track->modificationTime());
CPPUNIT_ASSERT_EQUAL("YUV 4:2:0"s, string(track->chromaFormat()));
CPPUNIT_ASSERT_EQUAL(1, track->duration().seconds());
break;
case 2:
CPPUNIT_ASSERT_EQUAL("SoundHandle"s, track->name());
CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Aac, track->format().general);
CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(SubFormats::AacMpeg4LowComplexityProfile), track->format().sub);
CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(0), track->format().extension);
CPPUNIT_ASSERT_EQUAL(static_cast<std::uint16_t>(2), track->channelCount());
CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(Mpeg4ChannelConfigs::FrontLeftFrontRight), track->channelConfig());
CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(0), track->extensionChannelConfig());
CPPUNIT_ASSERT_EQUAL(48000u, track->samplingFrequency());
CPPUNIT_ASSERT_EQUAL(0u, track->extensionSamplingFrequency());
CPPUNIT_ASSERT_EQUAL(static_cast<std::uint16_t>(16), track->bitsPerSample());
CPPUNIT_ASSERT_EQUAL(static_cast<std::uint64_t>(76), track->sampleCount());
CPPUNIT_ASSERT_EQUAL(DateTime::fromDateAndTime(2018, 7, 8, 20, 3, 52), track->creationTime());
CPPUNIT_ASSERT_EQUAL(DateTime::fromDateAndTime(2018, 7, 8, 20, 3, 52), track->modificationTime());
CPPUNIT_ASSERT_EQUAL(1, track->duration().seconds());
CPPUNIT_ASSERT_EQUAL(256.0, track->bitrate());
break;
case 3:
CPPUNIT_ASSERT_EQUAL("MetaHandler"s, track->name());
CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Unknown, track->format().general);
CPPUNIT_ASSERT_EQUAL("urim"s, track->formatId());
break;
default:
CPPUNIT_FAIL("unknown track ID");
}
}
const auto tags = m_fileInfo.tags();
switch (m_tagStatus) {
case TagStatus::Original:
CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
break;
case TagStatus::TestMetaDataPresent:
checkMp4TestMetaData();
break;
case TagStatus::Removed:
CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
}
CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
}
/*!
* \brief Checks whether test meta data for MP4 files has been applied correctly.
*/
void OverallTests::checkMp4TestMetaData()
{
// check whether a tag is assigned
const auto tags = m_fileInfo.tags();
Mp4Tag *tag = m_fileInfo.mp4Tag();
CPPUNIT_ASSERT_EQUAL(1_st, tags.size());
CPPUNIT_ASSERT(tag != nullptr);
// check test meta data
CPPUNIT_ASSERT_EQUAL(m_testTitle, tag->value(KnownField::Title));
CPPUNIT_ASSERT_EQUAL(m_testComment.toString(), tag->value(KnownField::Comment).toString()); // loss of description is ok
CPPUNIT_ASSERT_EQUAL(m_testAlbum, tag->value(KnownField::Album));
CPPUNIT_ASSERT_EQUAL(m_preservedMetaData.front(), tag->value(KnownField::Artist));
CPPUNIT_ASSERT_EQUAL(m_testPosition, tag->value(KnownField::TrackPosition));
CPPUNIT_ASSERT_EQUAL(m_testPosition, tag->value(KnownField::DiskPosition));
// TODO: check more fields
m_preservedMetaData.pop();
}
/*!
* \brief Checks whether padding and element position constraints are met.
*/
void OverallTests::checkMp4Constraints()
{
using namespace Mp4TestFlags;
CPPUNIT_ASSERT(m_fileInfo.container());
if (m_mode & PaddingConstraints) {
if (m_mode & ForceRewring) {
CPPUNIT_ASSERT_EQUAL(static_cast<std::uint64_t>(4096), m_fileInfo.paddingSize());
} else {
CPPUNIT_ASSERT(m_fileInfo.paddingSize() >= 1024);
CPPUNIT_ASSERT(m_fileInfo.paddingSize() <= (4096 + 1024));
}
if (!(m_mode & RemoveTagOrTrack) && (m_fileInfo.container()->documentType() != "dash")
&& ((m_mode & ForceRewring) || (m_mode & ForceTagPos))) {
const ElementPosition currentTagPos = m_fileInfo.container()->determineTagPosition(m_diag);
if (currentTagPos == ElementPosition::Keep) {
CPPUNIT_ASSERT_EQUAL(m_expectedTagPos, m_fileInfo.container()->determineIndexPosition(m_diag));
}
}
}
}
/*!
* \brief Sets test meta data in the file to be tested.
*/
void OverallTests::setMp4TestMetaData()
{
// ensure a tag exists
Tag *tag = m_fileInfo.container()->createTag();
// assign test meta data
tag->setValue(KnownField::Title, m_testTitle);
tag->setValue(KnownField::Comment, m_testComment);
tag->setValue(KnownField::Album, m_testAlbum);
m_preservedMetaData.push(tag->value(KnownField::Artist));
tag->setValue(KnownField::TrackPosition, m_testPosition);
tag->setValue(KnownField::DiskPosition, m_testPosition);
// TODO: set more fields
}
/*!
* \brief Alters the tracks of the file to be testd.
*
* - Adds track from mtx-test-data/mp4/10-DanseMacabreOp.40.m4a
* - Sets the language of the 2nd track to German
* - Sets the name of the 2nd track to "test".
*/
void OverallTests::alterMp4Tracks()
{
m_additionalFileInfo.setPath(testFilePath("mtx-test-data/mp4/10-DanseMacabreOp.40.m4a"));
m_additionalFileInfo.reopen(true);
m_additionalFileInfo.parseContainerFormat(m_diag);
m_additionalFileInfo.parseTracks(m_diag);
CPPUNIT_ASSERT_EQUAL(ContainerFormat::Mp4, m_additionalFileInfo.containerFormat());
CPPUNIT_ASSERT_EQUAL(ContainerFormat::Mp4, m_fileInfo.containerFormat());
const auto &tracks = m_additionalFileInfo.tracks();
CPPUNIT_ASSERT_EQUAL(1_st, tracks.size());
CPPUNIT_ASSERT_EQUAL(TrackType::Mp4Track, tracks[0]->type());
auto *track = static_cast<Mp4Track *>(tracks[0]);
CPPUNIT_ASSERT(static_cast<Mp4Container *>(m_additionalFileInfo.container())->removeTrack(track));
CPPUNIT_ASSERT_EQUAL(0_st, m_additionalFileInfo.trackCount());
track->setName("new track");
auto *container = static_cast<Mp4Container *>(m_fileInfo.container());
CPPUNIT_ASSERT_EQUAL(5_st, container->trackCount());
container->addTrack(track);
CPPUNIT_ASSERT_EQUAL(6_st, container->trackCount());
auto &secondTrack = container->tracks()[1];
secondTrack->setLocale(Locale("ger"sv, LocaleFormat::ISO_639_2_T));
secondTrack->setName("test");
}
/*!
* \brief Tests the MP4 parser via MediaFileInfo.
*/
void OverallTests::testMp4Parsing()
{
cerr << endl << "MP4 parser" << endl;
m_fileInfo.setForceFullParse(false);
m_tagStatus = TagStatus::Original;
parseFile(testFilePath("mtx-test-data/mp4/10-DanseMacabreOp.40.m4a"), &OverallTests::checkMp4Testfile1);
parseFile(testFilePath("mtx-test-data/mp4/1080p-DTS-HD-7.1.mp4"), &OverallTests::checkMp4Testfile2);
parseFile(testFilePath("mtx-test-data/mp4/dash/dragon-age-inquisition-H1LkM6IVlm4-video.mp4"), &OverallTests::checkMp4Testfile3);
parseFile(testFilePath("mtx-test-data/alac/othertest-itunes.m4a"), &OverallTests::checkMp4Testfile4);
parseFile(testFilePath("mtx-test-data/aac/he-aacv2-ps.m4a"), &OverallTests::checkMp4Testfile5);
parseFile(testFilePath("mp4/android-8.1-camera-recoding.mp4"), &OverallTests::checkMp4Testfile7);
}
/*!
* \brief Tests the MP4 maker via MediaFileInfo.
* \remarks Relies on the parser to check results.
*/
void OverallTests::testMp4Making()
{
// full parse is required to determine padding
m_fileInfo.setForceFullParse(true);
// do the test under different conditions
for (m_mode = 0; m_mode != 0x20; ++m_mode) {
using namespace Mp4TestFlags;
// setup test conditions
m_fileInfo.setForceRewrite(m_mode & ForceRewring);
if (m_mode & KeepTagPos) {
m_fileInfo.setTagPosition(ElementPosition::Keep);
} else {
m_fileInfo.setTagPosition(m_mode & TagsBeforeData ? ElementPosition::BeforeData : ElementPosition::AfterData);
}
m_fileInfo.setIndexPosition(m_fileInfo.tagPosition());
m_fileInfo.setPreferredPadding(m_mode & PaddingConstraints ? 4096 : 0);
m_fileInfo.setMinPadding(m_mode & PaddingConstraints ? 1024 : 0);
m_fileInfo.setMaxPadding(m_mode & PaddingConstraints ? (4096 + 1024) : numeric_limits<size_t>::max());
m_fileInfo.setForceTagPosition(m_mode & ForceTagPos);
m_fileInfo.setForceIndexPosition(m_mode & ForceTagPos);
// print test conditions
list<string> testConditions;
if (m_mode & ForceRewring) {
testConditions.emplace_back("forcing rewrite");
}
if (m_mode & KeepTagPos) {
if (m_mode & RemoveTagOrTrack) {
testConditions.emplace_back("removing tag");
} else {
testConditions.emplace_back("keeping tag position");
}
} else if (m_mode & TagsBeforeData) {
testConditions.emplace_back("tags before data");
} else {
testConditions.emplace_back("tags after data");
}
if (m_mode & PaddingConstraints) {
testConditions.emplace_back("padding constraints");
}
if (m_mode & ForceTagPos) {
testConditions.emplace_back("forcing tag position");
}
cerr << endl << "MP4 maker - testmode " << m_mode << ": " << joinStrings(testConditions, ", ") << endl;
// do actual tests
// -> either remove tags or set test meta data
m_tagStatus = (m_mode & RemoveTagOrTrack) ? TagStatus::Removed : TagStatus::TestMetaDataPresent;
void (OverallTests::*modifyRoutine)(void) = (m_mode & RemoveTagOrTrack) ? &OverallTests::removeAllTags : &OverallTests::setMp4TestMetaData;
makeFile(workingCopyPath("mtx-test-data/mp4/10-DanseMacabreOp.40.m4a"), modifyRoutine, &OverallTests::checkMp4Testfile1);
makeFile(workingCopyPath("mtx-test-data/mp4/1080p-DTS-HD-7.1.mp4"), modifyRoutine, &OverallTests::checkMp4Testfile2);
makeFile(
workingCopyPath("mtx-test-data/mp4/dash/dragon-age-inquisition-H1LkM6IVlm4-video.mp4"), modifyRoutine, &OverallTests::checkMp4Testfile3);
makeFile(workingCopyPath("mtx-test-data/alac/othertest-itunes.m4a"), modifyRoutine, &OverallTests::checkMp4Testfile4);
makeFile(workingCopyPath("mtx-test-data/aac/he-aacv2-ps.m4a"), modifyRoutine, &OverallTests::checkMp4Testfile5);
makeFile(workingCopyPath("mp4/android-8.1-camera-recoding.mp4"), modifyRoutine, &OverallTests::checkMp4Testfile7);
// -> add/remove tracks
modifyRoutine = (m_mode & RemoveTagOrTrack) ? &OverallTests::removeSecondTrack : &OverallTests::alterMp4Tracks;
m_fileInfo.setTagPosition(ElementPosition::Keep);
makeFile(workingCopyPath("mtx-test-data/mp4/1080p-DTS-HD-7.1.mp4"), modifyRoutine, &OverallTests::checkMp4Testfile6);
}
}