Tag Parser 11.0.0
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
overallogg.cpp
Go to the documentation of this file.
1#include "./helper.h"
2#include "./overall.h"
3
4#include "../abstracttrack.h"
5#include "../tag.h"
6#include "../vorbis/vorbiscomment.h"
7
8#include <c++utilities/io/misc.h>
9
10#include <functional>
11
12using namespace CppUtilities;
13
17void OverallTests::checkOggTestfile1()
18{
19 CPPUNIT_ASSERT_EQUAL(ContainerFormat::Ogg, m_fileInfo.containerFormat());
20 const auto tracks = m_fileInfo.tracks();
21 CPPUNIT_ASSERT_EQUAL(2_st, tracks.size());
22 for (const auto &track : tracks) {
23 switch (track->id()) {
24 case 897658443:
25 CPPUNIT_ASSERT_EQUAL(MediaType::Video, track->mediaType());
26 CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Theora, track->format().general);
27 break;
28 case 1755441791:
29 CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
30 CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Vorbis, track->format().general);
31 CPPUNIT_ASSERT_EQUAL(static_cast<std::uint16_t>(2), track->channelCount());
32 CPPUNIT_ASSERT_EQUAL(44100u, track->samplingFrequency());
33 CPPUNIT_ASSERT_EQUAL(4, track->duration().minutes());
34 break;
35 default:
36 CPPUNIT_FAIL("unknown track ID");
37 }
38 }
39 const auto tags = m_fileInfo.tags();
40 switch (m_tagStatus) {
42 CPPUNIT_ASSERT(m_fileInfo.hasAnyTag());
43 CPPUNIT_ASSERT_EQUAL(1_st, tags.size());
44 CPPUNIT_ASSERT_EQUAL("ffmpeg2theora 0.13"s, tags.front()->value(KnownField::Encoder).toString());
45 // Theora tags are currently not supported and hence only the Vorbis comment is
46 // taken into account here
47 break;
49 checkOggTestMetaData();
50 break;
52 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
53 }
54
55 CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
56}
57
61void OverallTests::checkOggTestfile2()
62{
63 CPPUNIT_ASSERT_EQUAL(ContainerFormat::Ogg, m_fileInfo.containerFormat());
64 const auto tracks = m_fileInfo.tracks();
65 CPPUNIT_ASSERT_EQUAL(1_st, tracks.size());
66 for (const auto &track : tracks) {
67 switch (track->id()) {
68 case 1375632254:
69 CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
70 CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Opus, track->format().general);
71 CPPUNIT_ASSERT_EQUAL(static_cast<std::uint16_t>(2), track->channelCount());
72 CPPUNIT_ASSERT_EQUAL(48000u, track->samplingFrequency());
73 CPPUNIT_ASSERT_EQUAL(1, track->duration().minutes());
74 break;
75 default:
76 CPPUNIT_FAIL("unknown track ID");
77 }
78 }
79 const auto tags = m_fileInfo.tags();
80 switch (m_tagStatus) {
82 CPPUNIT_ASSERT(m_fileInfo.hasAnyTag());
83 CPPUNIT_ASSERT_EQUAL(1_st, tags.size());
84 CPPUNIT_ASSERT_EQUAL("opusenc from opus-tools 0.1.6"s, tags.front()->value(KnownField::Encoder).toString());
85 break;
87 checkOggTestMetaData();
88 break;
90 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
91 }
92
93 CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
94}
95
99void OverallTests::checkOggTestfile3()
100{
101 CPPUNIT_ASSERT_EQUAL(ContainerFormat::Ogg, m_fileInfo.containerFormat());
102 const auto tracks = m_fileInfo.tracks();
103 CPPUNIT_ASSERT_EQUAL(1_st, tracks.size());
104 for (const auto &track : tracks) {
105 switch (track->id()) {
106 case 1843569915:
107 CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
108 CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Opus, track->format().general);
109 CPPUNIT_ASSERT_EQUAL(static_cast<std::uint16_t>(2), track->channelCount());
110 CPPUNIT_ASSERT_EQUAL(48000u, track->samplingFrequency());
111 CPPUNIT_ASSERT_EQUAL(TimeSpan::fromSeconds(19.461), track->duration());
112 break;
113 default:
114 CPPUNIT_FAIL("unknown track ID");
115 }
116 }
117 const auto tags = m_fileInfo.tags();
118 switch (m_tagStatus) {
120 CPPUNIT_ASSERT(m_fileInfo.hasAnyTag());
121 CPPUNIT_ASSERT_EQUAL(1_st, tags.size());
122 CPPUNIT_ASSERT_EQUAL("Lavf58.76.100"s, tags.front()->value(KnownField::Encoder).toString());
123 CPPUNIT_ASSERT_EQUAL("eng"s, tags.front()->value(KnownField::Language).toString());
124 [[fallthrough]];
126 checkOggTestMetaDataCover();
127 break;
129 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
130 }
131
132 if (m_tagStatus != TagStatus::Original) {
133 CPPUNIT_ASSERT_MESSAGE("no warnings for non-broken file", m_diag.level() <= DiagLevel::Information);
134 return;
135 }
136 CPPUNIT_ASSERT_EQUAL_MESSAGE("warning present", DiagLevel::Warning, m_diag.level());
137 for (const auto &msg : m_diag) {
138 if (msg.level() == DiagLevel::Warning) {
139 CPPUNIT_ASSERT_EQUAL_MESSAGE("warning due to broken segment termination", "3 bytes left in last segment."s, msg.message());
140 CPPUNIT_ASSERT_EQUAL_MESSAGE("warning relates to Vorbis comment", "parsing Vorbis comment"s, msg.context());
141 break;
142 }
143 }
144}
145
149void OverallTests::checkOggTestMetaData()
150{
151 // check whether a tag is assigned
152 const auto tags = m_fileInfo.tags();
153 const auto *const tag = m_fileInfo.vorbisComment();
154 CPPUNIT_ASSERT_EQUAL(1_st, tags.size());
155 CPPUNIT_ASSERT(tag != nullptr);
156
157 // check test meta data
158 CPPUNIT_ASSERT_EQUAL(m_testTitle, tag->value(KnownField::Title));
159 CPPUNIT_ASSERT_EQUAL(m_testComment.toString(), tag->value(KnownField::Comment).toString()); // loss of description is ok
160 CPPUNIT_ASSERT_EQUAL(m_testAlbum, tag->value(KnownField::Album));
161 CPPUNIT_ASSERT_EQUAL(m_preservedMetaData.front(), tag->value(KnownField::Artist));
162 CPPUNIT_ASSERT_EQUAL(m_testPosition, tag->value(KnownField::TrackPosition));
163 CPPUNIT_ASSERT_EQUAL(m_testPosition, tag->value(KnownField::DiskPosition));
164 // TODO: check more fields
165 m_preservedMetaData.pop();
166}
167
168void OverallTests::checkOggTestMetaDataCover()
169{
170 // check whether a tag is assigned
171 const auto tags = m_fileInfo.tags();
172 const auto *const tag = m_fileInfo.vorbisComment();
173 CPPUNIT_ASSERT_EQUAL(1_st, tags.size());
174 CPPUNIT_ASSERT(tag != nullptr);
175
176 const auto expectedCoverData = readFile(testFilePath("ogg/example-cover.png"));
177 CPPUNIT_ASSERT_EQUAL_MESSAGE("expected cover assigned", std::string_view(expectedCoverData), tag->value(KnownField::Cover).data());
178}
179
180void OverallTests::setOggTestMetaData()
181{
182 // ensure a tag exists
183 auto *const tag = m_fileInfo.createVorbisComment();
184
185 // assign test meta data
186 tag->setValue(KnownField::Title, m_testTitle);
187 tag->setValue(KnownField::Comment, m_testComment);
188 tag->setValue(KnownField::Album, m_testAlbum);
189 m_preservedMetaData.push(tag->value(KnownField::Artist));
190 tag->setValue(KnownField::TrackPosition, m_testPosition);
191 tag->setValue(KnownField::DiskPosition, m_testPosition);
192 // TODO: set more fields
193}
194
195void OverallTests::setOggTestMetaDataCover()
196{
197 auto *const tag = m_fileInfo.createVorbisComment();
198 const auto cover = readFile(testFilePath("ogg/example-cover.png"));
199 tag->setValue(KnownField::Cover, TagValue(cover.data(), cover.size(), TagDataType::Picture));
200}
201
207{
208 cerr << endl << "OGG parser" << endl;
209 m_fileInfo.setForceFullParse(false);
210 m_tagStatus = TagStatus::Original;
211 parseFile(testFilePath("mtx-test-data/ogg/qt4dance_medium.ogg"), &OverallTests::checkOggTestfile1);
212 parseFile(testFilePath("mtx-test-data/opus/v-opus.ogg"), &OverallTests::checkOggTestfile2);
213 parseFile(testFilePath("ogg/noise-broken-segment-termination.opus"), &OverallTests::checkOggTestfile3);
214}
215
223{
224 // full parse is required to determine padding
225 m_fileInfo.setForceFullParse(true);
226
227 // do the test under different conditions
228 for (m_mode = 0; m_mode != 0x2; ++m_mode) {
229 using namespace SimpleTestFlags;
230
231 // no need to setup test conditions because the Ogg maker
232 // doesn't take those settings into account (currently)
233
234 // print test conditions
235 list<string> testConditions;
236 if (m_mode & RemoveTag) {
237 testConditions.emplace_back("removing tag");
238 } else {
239 testConditions.emplace_back("modifying tag");
240 }
241 cerr << endl << "OGG maker - testmode " << m_mode << ": " << joinStrings(testConditions, ", ") << endl;
242
243 // do actual tests
245 const auto modifyRoutine = (m_mode & RemoveTag) ? &OverallTests::removeAllTags : &OverallTests::setOggTestMetaData;
246 const auto modifyRoutineCover = (m_mode & RemoveTag) ? &OverallTests::removeAllTags : &OverallTests::setOggTestMetaDataCover;
247 makeFile(workingCopyPath("mtx-test-data/ogg/qt4dance_medium.ogg"), modifyRoutine, &OverallTests::checkOggTestfile1);
248 makeFile(workingCopyPath("mtx-test-data/opus/v-opus.ogg"), modifyRoutine, &OverallTests::checkOggTestfile2);
249 makeFile(workingCopyPath("ogg/noise-without-cover.opus"), modifyRoutineCover, &OverallTests::checkOggTestfile3);
250 }
251}
void testOggParsing()
Tests the Ogg parser via MediaFileInfo.
Definition: overallogg.cpp:206
void testOggMaking()
Tests the Ogg maker via MediaFileInfo.
Definition: overallogg.cpp:222
DiagLevel level() const
Returns the worst diag level present in the container.
Definition: diagnostics.cpp:55
std::vector< AbstractTrack * > tracks() const
Returns the tracks for the current file.
VorbisComment * createVorbisComment()
Creates a Vorbis comment for the current file.
VorbisComment * vorbisComment() const
Returns a pointer to the first assigned Vorbis comment or nullptr if none is assigned.
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.
ContainerFormat containerFormat() const
Returns the container format of the current file.
bool hasAnyTag() const
Returns an indication whether a tag of any format is assigned.
The TagValue class wraps values of different types.
Definition: tagvalue.h:95
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:485
bool setValue(KnownField field, const TagValue &value) override
Assigns the given value to the specified field.
constexpr TAG_PARSER_EXPORT std::string_view cover()
@ TestMetaDataPresent