Tag Parser  6.4.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 "../mediafileinfo.h"
4 #include "../abstracttrack.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 Media;
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  MediaFileInfo file(testFilePath("unsupported.bin"));
91  file.parseContainerFormat();
92  file.parseTags();
93  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotSupported, file.containerParsingStatus());
94  // NOTE: parsing tags of unsupported container is actually supported: there is nothing to do
95  // but maybe not what one would expect?
96  CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.tagsParsingStatus());
97  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.tracksParsingStatus());
98  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.chaptersParsingStatus());
99  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.attachmentsParsingStatus());
100  CPPUNIT_ASSERT_EQUAL(ContainerFormat::Unknown, file.containerFormat());
101  file.invalidate();
102 }
103 
105 {
106  MediaFileInfo file(testFilePath("mtx-test-data/aac/he-aacv2-ps.m4a"));
107  file.open(true);
108  file.parseContainerFormat();
109  file.parseTags();
110  file.parseAttachments();
111  file.close();
112  try {
113  file.parseTracks();
114  CPPUNIT_FAIL("expected std::ios_base::failure because file has been closed");
115  } catch(...) {
116  catchIoFailure();
117  }
118  CPPUNIT_ASSERT(file.areTagsSupported());
119  CPPUNIT_ASSERT(file.areTracksSupported());
120  CPPUNIT_ASSERT(!file.areChaptersSupported());
121  CPPUNIT_ASSERT(!file.areAttachmentsSupported());
122  CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.containerParsingStatus());
123  CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.tagsParsingStatus());
124  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.tracksParsingStatus());
125  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.chaptersParsingStatus());
126  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotSupported, file.attachmentsParsingStatus());
127  CPPUNIT_ASSERT_EQUAL(0_st, file.trackCount());
128  CPPUNIT_ASSERT_EQUAL(ContainerFormat::Mp4, file.containerFormat());
129  CPPUNIT_ASSERT_EQUAL(NotificationList({
130  Notification(NotificationType::Information,
131  "Parsing attachments is not implemented for the container format of the file.",
132  "parsing attachments")
133  }), file.gatherRelatedNotifications());
134  CPPUNIT_ASSERT_EQUAL(NotificationType::Information, file.worstNotificationTypeIncludingRelatedObjects());
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  MediaFileInfo file(testFilePath("matroska_wave1/test1.mkv"));
157  file.open(true);
158  file.parseEverything();
159  // calling parse methods twice should not do anything (and hence can not fail anymore because the file has already been closed)
160  file.close();
161  file.parseEverything();
162  CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.containerParsingStatus());
163  CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.tagsParsingStatus());
164  CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.tracksParsingStatus());
165  CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.chaptersParsingStatus());
166  CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.attachmentsParsingStatus());
167  CPPUNIT_ASSERT_EQUAL(ContainerFormat::Matroska, file.containerFormat());
168 
169  // general info
170  CPPUNIT_ASSERT(file.container());
171  CPPUNIT_ASSERT(file.areTagsSupported());
172  CPPUNIT_ASSERT(file.hasAnyTag());
173  CPPUNIT_ASSERT_EQUAL(1_st, file.tags().size());
174  CPPUNIT_ASSERT_EQUAL(1_st, file.matroskaTags().size());
175  CPPUNIT_ASSERT(!file.mp4Tag());
176  CPPUNIT_ASSERT(!file.vorbisComment());
177  CPPUNIT_ASSERT(file.areTracksSupported());
178  CPPUNIT_ASSERT_EQUAL(2_st, file.trackCount());
179  CPPUNIT_ASSERT(file.areChaptersSupported());
180  CPPUNIT_ASSERT_EQUAL(0_st, file.chapters().size());
181  CPPUNIT_ASSERT(file.areAttachmentsSupported());
182  CPPUNIT_ASSERT_EQUAL(0_st, file.attachments().size());
183 
184  // notifications
185  CPPUNIT_ASSERT(!file.hasNotifications());
186  CPPUNIT_ASSERT(!file.haveRelatedObjectsNotifications());
187  CPPUNIT_ASSERT_EQUAL(NotificationList(), file.gatherRelatedNotifications());
189  file.container()->addNotification(NotificationType::Warning, "warning", "test");
190  CPPUNIT_ASSERT(file.haveRelatedObjectsNotifications());
191  CPPUNIT_ASSERT_EQUAL(NotificationType::Warning, file.worstNotificationTypeIncludingRelatedObjects());
192  file.tags().back()->addNotification(NotificationType::Critical, "error", "test");
193  CPPUNIT_ASSERT_EQUAL(NotificationType::Critical, file.worstNotificationTypeIncludingRelatedObjects());
194  CPPUNIT_ASSERT(file.haveRelatedObjectsNotifications());
195  CPPUNIT_ASSERT_EQUAL(2_st, file.gatherRelatedNotifications().size());
196 
197  // track info / available languages
198  file.tracks().back()->setLanguage("eng");
199  CPPUNIT_ASSERT_EQUAL(unordered_set<string>({"eng"}), file.availableLanguages());
200  CPPUNIT_ASSERT_EQUAL(unordered_set<string>({}), file.availableLanguages(MediaType::Text));
201  CPPUNIT_ASSERT_EQUAL("ID: 2422994868, type: Video"s, file.tracks()[0]->label());
202  CPPUNIT_ASSERT_EQUAL("ID: 3653291187, type: Audio, language: \"eng\""s, file.tracks()[1]->label());
203  CPPUNIT_ASSERT_EQUAL("MS-MPEG-4-480p / MP3-2ch-eng"s, file.technicalSummary());
204 }
std::unordered_set< std::string > availableLanguages(Media::MediaType type=Media::MediaType::Audio) const
Determines the available languages for specified media type (by default MediaType::Audio).
bool areTagsSupported() const
Returns an indication whether this library supports the tag format of the current file...
void parseTracks()
Parses the tracks of the current file.
void testParsingUnsupportedFile()
AbstractContainer * container() const
Returns the container for the current file.
void tags(std::vector< Tag *> &tags) const
Stores all tags assigned to the current file in the specified vector.
ParsingStatus tagsParsingStatus() const
Returns an indication whether tag information has been parsed yet.
const std::vector< std::unique_ptr< Id3v2Tag > > & id3v2Tags() const
Returns pointers to the assigned ID3v2 tags.
bool isOpen() const
Indicates whether a std::fstream is open for the current file.
Definition: basicfileinfo.h:64
Id3v1Tag * id3v1Tag() const
Returns a pointer to the assigned ID3v1 tag or nullptr if none is assigned.
void parseTags()
Parses the tag(s) of the current file.
static std::string containingDirectory(const std::string &path)
Returns the path of the directory containing the given file.
STL namespace.
const std::vector< std::unique_ptr< MatroskaTag > > & matroskaTags() const
Returns pointers to the assigned Matroska tags.
VorbisComment * createVorbisComment()
Creates a Vorbis comment for the current file.
void addNotification(const Notification &notification)
This protected method is meant to be called by the derived class to add a notification.
bool hasAnyTag() const
Returns an indication whether a tag of any format is assigned.
void reportPathChanged(const std::string &newPath)
Call this function to report that the path changed.
uint64 size() const
Returns size of the current file in bytes.
CPPUNIT_TEST_SUITE_REGISTRATION(MediaFileInfoTests)
void testFullParseAndFurtherProperties()
void testPartialParsingAndTagCreationOfMp4File()
void open(bool readOnly=false)
Opens a std::fstream for the current file.
void parseAttachments()
Parses the attachments of the current file.
bool areAttachmentsSupported() const
Returns an indication whether this library supports attachment format of the current file...
std::vector< AbstractChapter * > chapters() const
Returns all chapters assigned to the current file.
void close()
A possibly opened std::fstream will be closed.
bool hasNotifications() const
Returns an indication whether there are notifications for the current object.
NotificationType worstNotificationTypeIncludingRelatedObjects() const
Returns the worst notification type including related objects such as track, tag and container...
Contains utility classes helping to read and write streams.
std::vector< AbstractTrack * > tracks() const
Returns the tracks for the current file.
bool isReadOnly() const
Indicates whether the last open()/reopen() call was read-only.
Definition: basicfileinfo.h:72
static std::string fileName(const std::string &path, bool cutExtension=false)
Returns the file name of the given file.
void invalidate()
Invalidates the file info manually.
std::string technicalSummary() const
Generates a short technical summary about the file&#39;s tracks.
std::vector< AbstractAttachment * > attachments() const
Returns all attachments assigned to the current file.
ParsingStatus attachmentsParsingStatus() const
Returns whether the attachments have been parsed yet.
bool removeVorbisComment()
Removes all assigned Vorbis comment from the current file.
bool haveRelatedObjectsNotifications() const
Returns an indication whether at least one related object (track, tag, container) has notifications...
ParsingStatus tracksParsingStatus() const
Returns an indication whether tracks have been parsed yet.
ParsingStatus containerParsingStatus() const
Returns an indication whether the container format has been parsed yet.
std::list< Notification > NotificationList
Definition: notification.h:39
void parseContainerFormat()
Parses the container format of the current file.
VorbisComment * vorbisComment() const
Returns a pointer to the first assigned Vorbis comment or nullptr if none is assigned.
The MediaFileInfo class allows to read and write tag information providing a container/tag format ind...
Definition: mediafileinfo.h:53
void parseEverything()
Parses the container format, the tracks and the tag information of the current file.
The MediaFileInfoTests tests convenience methods provided by MediaFileInfo.
The Notification class holds a notification message of a certain notification type.
Definition: notification.h:43
Id3v2Tag * createId3v2Tag()
Creates an ID3v2 tag for the current file.
Id3v1Tag * createId3v1Tag()
Creates an ID3v1 tag for the current file.
static std::string extension(const std::string &path)
Returns the extension of the given file.
bool areTracksSupported() const
Returns an indication whether this library supports parsing the tracks information of the current fil...
static std::string pathWithoutExtension(const std::string &fullPath)
Returns a copy of the given path without the extension/suffix.
void gatherRelatedNotifications(NotificationList &notifications) const
Returns the notifications of the current instance and all related objects (tracks, tags, container, ...).
Mp4Tag * mp4Tag() const
Returns a pointer to the assigned MP4 tag or nullptr if none is assigned.
Contains all classes and functions of the TagInfo library.
Definition: exceptions.h:9
bool createAppropriateTags(bool treatUnknownFilesAsMp3Files=false, TagUsage id3v1usage=TagUsage::KeepExisting, TagUsage id3v2usage=TagUsage::Always, bool id3InitOnCreate=false, bool id3TransferValuesOnRemoval=true, bool mergeMultipleSuccessiveId3v2Tags=true, bool keepExistingId3v2version=true, byte id3v2MajorVersion=3, const std::vector< TagTarget > &requiredTargets=std::vector< TagTarget >())
Ensures appropriate tags are created according the given specifications.
ContainerFormat containerFormat() const
Returns the container format of the current file.
bool areChaptersSupported() const
Returns an indication whether this library supports parsing the chapters of the current file...
std::size_t trackCount() const
Returns the number of tracks that could be parsed.
ParsingStatus chaptersParsingStatus() const
Returns whether the chapters have been parsed yet.