Tag Parser  7.0.0
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
mediafileinfo.cpp
Go to the documentation of this file.
1 #include "./helper.h"
2 
3 #include "../abstracttrack.h"
4 #include "../mediafileinfo.h"
5 #include "../tag.h"
6 
7 #include <c++utilities/io/catchiofailure.h>
8 #include <c++utilities/tests/testutils.h>
9 using namespace TestUtilities;
10 
11 #include <cppunit/TestFixture.h>
12 #include <cppunit/extensions/HelperMacros.h>
13 
14 #include <cstdio>
15 
16 using namespace std;
17 using namespace TagParser;
18 using namespace IoUtilities;
19 using namespace TestUtilities::Literals;
20 
21 using namespace CPPUNIT_NS;
22 
27 class MediaFileInfoTests : public TestFixture {
28  CPPUNIT_TEST_SUITE(MediaFileInfoTests);
29  CPPUNIT_TEST(testInitialStatus);
30  CPPUNIT_TEST(testFileSystemMethods);
31  CPPUNIT_TEST(testParsingUnsupportedFile);
32  CPPUNIT_TEST(testFullParseAndFurtherProperties);
33  CPPUNIT_TEST_SUITE_END();
34 
35 public:
36  void setUp();
37  void tearDown();
38 
39  void testInitialStatus();
40  void testFileSystemMethods();
41  void testParsingUnsupportedFile();
42  void testPartialParsingAndTagCreationOfMp4File();
43 
44  void testFullParseAndFurtherProperties();
45 };
46 
48 
50 {
51 }
52 
54 {
55 }
56 
58 {
59  const MediaFileInfo file;
60  CPPUNIT_ASSERT(!file.areTagsSupported());
61  CPPUNIT_ASSERT(!file.areTracksSupported());
62  CPPUNIT_ASSERT(!file.areChaptersSupported());
63  CPPUNIT_ASSERT(!file.areAttachmentsSupported());
64  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.containerParsingStatus());
65  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.tagsParsingStatus());
66  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.tracksParsingStatus());
67  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.chaptersParsingStatus());
68  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.attachmentsParsingStatus());
69  CPPUNIT_ASSERT_EQUAL(ContainerFormat::Unknown, file.containerFormat());
70 }
71 
73 {
74  MediaFileInfo file("/usr/bin/unsupported.bin");
75  CPPUNIT_ASSERT_EQUAL("/usr/bin"s, file.containingDirectory());
76  CPPUNIT_ASSERT_EQUAL("unsupported.bin"s, file.fileName());
77  CPPUNIT_ASSERT_EQUAL("unsupported"s, file.fileName(true));
78  CPPUNIT_ASSERT_EQUAL("/usr/bin/unsupported"s, file.pathWithoutExtension());
79  CPPUNIT_ASSERT_EQUAL(".bin"s, file.extension());
80  CPPUNIT_ASSERT_EQUAL(static_cast<uint64>(0), file.size());
81  file.reportPathChanged(testFilePath("unsupported.bin"));
82  file.open(true);
83  CPPUNIT_ASSERT(file.isOpen());
84  CPPUNIT_ASSERT(file.isReadOnly());
85  CPPUNIT_ASSERT_EQUAL(static_cast<uint64>(41), file.size());
86 }
87 
89 {
90  Diagnostics diag;
91  MediaFileInfo file(testFilePath("unsupported.bin"));
92  file.parseContainerFormat(diag);
93  file.parseTags(diag);
94  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotSupported, file.containerParsingStatus());
95  // NOTE: parsing tags of unsupported container is actually supported: there is nothing to do
96  // but maybe not what one would expect?
97  CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.tagsParsingStatus());
98  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.tracksParsingStatus());
99  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.chaptersParsingStatus());
100  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.attachmentsParsingStatus());
101  CPPUNIT_ASSERT_EQUAL(ContainerFormat::Unknown, file.containerFormat());
102  file.invalidate();
103 }
104 
106 {
107  Diagnostics diag;
108  MediaFileInfo file(testFilePath("mtx-test-data/aac/he-aacv2-ps.m4a"));
109  file.open(true);
110  file.parseContainerFormat(diag);
111  file.parseTags(diag);
112  file.parseAttachments(diag);
113  file.close();
114  try {
115  file.parseTracks(diag);
116  CPPUNIT_FAIL("expected std::ios_base::failure because file has been closed");
117  } catch (...) {
118  catchIoFailure();
119  }
120  CPPUNIT_ASSERT(file.areTagsSupported());
121  CPPUNIT_ASSERT(file.areTracksSupported());
122  CPPUNIT_ASSERT(!file.areChaptersSupported());
123  CPPUNIT_ASSERT(!file.areAttachmentsSupported());
124  CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.containerParsingStatus());
125  CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.tagsParsingStatus());
126  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.tracksParsingStatus());
127  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.chaptersParsingStatus());
128  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotSupported, file.attachmentsParsingStatus());
129  CPPUNIT_ASSERT_EQUAL(0_st, file.trackCount());
130  CPPUNIT_ASSERT_EQUAL(ContainerFormat::Mp4, file.containerFormat());
131  CPPUNIT_ASSERT_EQUAL(Diagnostics({ DiagMessage(DiagLevel::Information,
132  "Parsing attachments is not implemented for the container format of the file.", "parsing attachments") }),
133  diag);
134  CPPUNIT_ASSERT_EQUAL(DiagLevel::Information, diag.level());
135 
136  // create/remove tag
137  CPPUNIT_ASSERT_EQUAL(0_st, file.matroskaTags().size());
138  CPPUNIT_ASSERT(!file.id3v1Tag());
139  CPPUNIT_ASSERT_EQUAL(0_st, file.id3v2Tags().size());
140  CPPUNIT_ASSERT(!file.vorbisComment());
141  CPPUNIT_ASSERT(!file.mp4Tag());
142  // NOTE: Maybe it should not be possible to create ID3 tags for MP4 file? It will be ignored anyways.
143  CPPUNIT_ASSERT(file.createId3v1Tag());
144  CPPUNIT_ASSERT(file.id3v1Tag());
145  CPPUNIT_ASSERT(file.createId3v2Tag());
146  CPPUNIT_ASSERT_EQUAL(1_st, file.id3v2Tags().size());
147  CPPUNIT_ASSERT(!file.createVorbisComment());
148  CPPUNIT_ASSERT(!file.vorbisComment());
149  CPPUNIT_ASSERT(!file.removeVorbisComment());
150  file.createAppropriateTags();
151  CPPUNIT_ASSERT(file.mp4Tag());
152 }
153 
155 {
156  Diagnostics diag;
157  MediaFileInfo file(testFilePath("matroska_wave1/test1.mkv"));
158  file.open(true);
159  file.parseEverything(diag);
160  // calling parse methods twice should not do anything (and hence can not fail anymore because the file has already been closed)
161  file.close();
162  file.parseEverything(diag);
163  CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.containerParsingStatus());
164  CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.tagsParsingStatus());
165  CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.tracksParsingStatus());
166  CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.chaptersParsingStatus());
167  CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.attachmentsParsingStatus());
168  CPPUNIT_ASSERT_EQUAL(ContainerFormat::Matroska, file.containerFormat());
169 
170  // general info
171  CPPUNIT_ASSERT(file.container());
172  CPPUNIT_ASSERT(file.areTagsSupported());
173  CPPUNIT_ASSERT(file.hasAnyTag());
174  CPPUNIT_ASSERT_EQUAL(1_st, file.tags().size());
175  CPPUNIT_ASSERT_EQUAL(1_st, file.matroskaTags().size());
176  CPPUNIT_ASSERT(!file.mp4Tag());
177  CPPUNIT_ASSERT(!file.vorbisComment());
178  CPPUNIT_ASSERT(file.areTracksSupported());
179  CPPUNIT_ASSERT_EQUAL(2_st, file.trackCount());
180  CPPUNIT_ASSERT(file.areChaptersSupported());
181  CPPUNIT_ASSERT_EQUAL(0_st, file.chapters().size());
182  CPPUNIT_ASSERT(file.areAttachmentsSupported());
183  CPPUNIT_ASSERT_EQUAL(0_st, file.attachments().size());
184 
185  // notifications
186  CPPUNIT_ASSERT_EQUAL(Diagnostics(), diag);
187  CPPUNIT_ASSERT_EQUAL(DiagLevel::None, diag.level());
188  diag.emplace_back(DiagLevel::Warning, "warning", "test");
189  CPPUNIT_ASSERT_EQUAL(DiagLevel::Warning, diag.level());
190  diag.emplace_back(DiagLevel::Critical, "error", "test");
191  CPPUNIT_ASSERT_EQUAL(DiagLevel::Critical, diag.level());
192 
193  // track info / available languages
194  file.tracks().back()->setLanguage("eng");
195  CPPUNIT_ASSERT_EQUAL(unordered_set<string>({ "eng" }), file.availableLanguages());
196  CPPUNIT_ASSERT_EQUAL(unordered_set<string>({}), file.availableLanguages(MediaType::Text));
197  CPPUNIT_ASSERT_EQUAL("ID: 2422994868, type: Video"s, file.tracks()[0]->label());
198  CPPUNIT_ASSERT_EQUAL("ID: 3653291187, type: Audio, language: \"eng\""s, file.tracks()[1]->label());
199  CPPUNIT_ASSERT_EQUAL("MS-MPEG-4-480p / MP3-2ch-eng"s, file.technicalSummary());
200 }
void parseEverything(Diagnostics &diag)
Parses the container format, the tracks and the tag information of the current file.
static std::string containingDirectory(const std::string &path)
Returns the path of the directory containing the given file.
void open(bool readOnly=false)
Opens a std::fstream for the current file.
const std::vector< std::unique_ptr< MatroskaTag > > & matroskaTags() const
Returns pointers to the assigned Matroska tags.
void testParsingUnsupportedFile()
Id3v1Tag * createId3v1Tag()
Creates an ID3v1 tag for the current file.
std::unordered_set< std::string > availableLanguages(TagParser::MediaType type=TagParser::MediaType::Audio) const
Determines the available languages for specified media type (by default MediaType::Audio).
Id3v1Tag * id3v1Tag() const
Returns a pointer to the assigned ID3v1 tag or nullptr if none is assigned.
VorbisComment * createVorbisComment()
Creates a Vorbis comment for the current file.
ParsingStatus tagsParsingStatus() const
Returns an indication whether tag information has been parsed yet.
std::size_t trackCount() const
Returns the number of tracks that could be parsed.
bool hasAnyTag() const
Returns an indication whether a tag of any format is assigned.
ParsingStatus attachmentsParsingStatus() const
Returns whether the attachments have been parsed yet.
const std::vector< std::unique_ptr< Id3v2Tag > > & id3v2Tags() const
Returns pointers to the assigned ID3v2 tags.
STL namespace.
ParsingStatus chaptersParsingStatus() const
Returns whether the chapters have been parsed yet.
CPPUNIT_TEST_SUITE_REGISTRATION(MediaFileInfoTests)
void testFullParseAndFurtherProperties()
void invalidate()
Invalidates the file info manually.
void testPartialParsingAndTagCreationOfMp4File()
ContainerFormat containerFormat() const
Returns the container format of the current file.
void parseAttachments(Diagnostics &diag)
Parses the attachments of the current file.
bool areTagsSupported() const
Returns an indication whether this library supports the tag format of the current file...
VorbisComment * vorbisComment() const
Returns a pointer to the first assigned Vorbis comment or nullptr if none is assigned.
bool removeVorbisComment()
Removes all assigned Vorbis comment from the current file.
bool isReadOnly() const
Indicates whether the last open()/reopen() call was read-only.
Definition: basicfileinfo.h:71
static std::string fileName(const std::string &path, bool cutExtension=false)
Returns the file name of the given file.
void parseTags(Diagnostics &diag)
Parses the tag(s) of the current file.
Contains utility classes helping to read and write streams.
bool areChaptersSupported() const
Returns an indication whether this library supports parsing the chapters of the current file...
DiagLevel level() const
Definition: diagnostics.cpp:32
static std::string extension(const std::string &path)
Returns the extension of the given file.
bool createAppropriateTags(const TagCreationSettings &settings=TagCreationSettings())
Ensures appropriate tags are created according the given settings.
void tags(std::vector< Tag *> &tags) const
Stores all tags assigned to the current file in the specified vector.
static std::string pathWithoutExtension(const std::string &fullPath)
Returns a copy of the given path without the extension/suffix.
void reportPathChanged(const std::string &newPath)
Call this function to report that the path changed.
std::vector< AbstractChapter * > chapters() const
Returns all chapters assigned to the current file.
void close()
A possibly opened std::fstream will be closed.
void parseTracks(Diagnostics &diag)
Parses the tracks of the current file.
ParsingStatus tracksParsingStatus() const
Returns an indication whether tracks have been parsed yet.
std::string technicalSummary() const
Generates a short technical summary about the file&#39;s tracks.
The MediaFileInfoTests tests convenience methods provided by MediaFileInfo.
AbstractContainer * container() const
Returns the container for the current file.
void parseContainerFormat(Diagnostics &diag)
Parses the container format of the current file.
Mp4Tag * mp4Tag() const
Returns a pointer to the assigned MP4 tag or nullptr if none is assigned.
ParsingStatus containerParsingStatus() const
Returns an indication whether the container format has been parsed yet.
uint64 size() const
Returns size of the current file in bytes.
bool areAttachmentsSupported() const
Returns an indication whether this library supports attachment format of the current file...
std::vector< AbstractAttachment * > attachments() const
Returns all attachments assigned to the current file.
bool areTracksSupported() const
Returns an indication whether this library supports parsing the tracks information of the current fil...
Id3v2Tag * createId3v2Tag()
Creates an ID3v2 tag for the current file.
bool isOpen() const
Indicates whether a std::fstream is open for the current file.
Definition: basicfileinfo.h:63
std::vector< AbstractTrack * > tracks() const
Returns the tracks for the current file.