368 lines
11 KiB
C++
368 lines
11 KiB
C++
#ifndef MEDIAINFO_H
|
|
#define MEDIAINFO_H
|
|
|
|
#include "./signature.h"
|
|
#include "./statusprovider.h"
|
|
#include "./basicfileinfo.h"
|
|
#include "./abstractcontainer.h"
|
|
|
|
#include <string>
|
|
#include <fstream>
|
|
#include <vector>
|
|
#include <memory>
|
|
|
|
namespace Media {
|
|
|
|
class Tag;
|
|
class Id3v1Tag;
|
|
class Id3v2Tag;
|
|
class Mp4Container;
|
|
class Mp4Atom;
|
|
class Mp4Tag;
|
|
class MatroskaContainer;
|
|
class OggContainer;
|
|
class EbmlElement;
|
|
class MatroskaTag;
|
|
class AbstractTrack;
|
|
class WaveAudioStream;
|
|
class MpegAudioFrameStream;
|
|
|
|
enum class MediaType;
|
|
enum class TagType : unsigned int;
|
|
|
|
/*!
|
|
* \brief The TagUsage enum specifies the usage of a certain tag type.
|
|
*/
|
|
enum class TagUsage
|
|
{
|
|
Always, /**< a tag of the type is always used; a new tag is created if none exists yet */
|
|
KeepExisting, /**< existing tags of the type are kept and updated but no new tag is created */
|
|
Never /**< tags of the type are never used; a possibly existing tag of the type is removed */
|
|
};
|
|
|
|
/*!
|
|
* \brief The ParsingStatus enum specifies whether a certain part of the file (tracks, tags, ...) has
|
|
* been parsed yet and if what the parsing result is.
|
|
*/
|
|
enum class ParsingStatus : byte
|
|
{
|
|
NotParsedYet, /**< the part has not been parsed yet */
|
|
Ok, /**< the part has been parsed and no critical errors occured */
|
|
NotSupported, /**< tried to parse the part, but the format is not supported */
|
|
CriticalFailure /**< tried to parse the part, but critical errors occured */
|
|
};
|
|
|
|
class LIB_EXPORT MediaFileInfo : public BasicFileInfo, public StatusProvider
|
|
{
|
|
public:
|
|
// constructor, destructor
|
|
MediaFileInfo();
|
|
MediaFileInfo(const std::string &path);
|
|
MediaFileInfo(const MediaFileInfo &) = delete;
|
|
MediaFileInfo &operator=(const MediaFileInfo &) = delete;
|
|
virtual ~MediaFileInfo();
|
|
|
|
// methods to parse file
|
|
void parseContainerFormat();
|
|
void parseTracks();
|
|
void parseTags();
|
|
void parseChapters();
|
|
void parseAttachments();
|
|
void parseEverything();
|
|
|
|
// methods to apply changes
|
|
void applyChanges();
|
|
|
|
// methods to get parsed information regarding ...
|
|
// ... the container
|
|
ContainerFormat containerFormat() const;
|
|
const char *containerFormatName() const;
|
|
const char *containerFormatAbbreviation() const;
|
|
const char *containerFormatSubversion() const;
|
|
const char *mimeType() const;
|
|
uint64 containerOffset() const;
|
|
uint64 paddingSize() const;
|
|
AbstractContainer *container() const;
|
|
ParsingStatus containerParsingStatus() const;
|
|
// ... the capters
|
|
ParsingStatus chaptersParsingStatus() const;
|
|
std::vector<AbstractChapter *> chapters() const;
|
|
bool areChaptersSupported() const;
|
|
// ... the attachments
|
|
ParsingStatus attachmentsParsingStatus() const;
|
|
std::vector<AbstractAttachment *> attachments() const;
|
|
bool areAttachmentsSupported() const;
|
|
// ... the tracks
|
|
ParsingStatus tracksParsingStatus() const;
|
|
std::size_t trackCount() const;
|
|
std::vector<AbstractTrack *> tracks() const;
|
|
bool hasTracksOfType(Media::MediaType type) const;
|
|
ChronoUtilities::TimeSpan duration() const;
|
|
bool areTracksSupported() const;
|
|
// ... the tags
|
|
ParsingStatus tagsParsingStatus() const;
|
|
bool hasId3v1Tag() const;
|
|
bool hasId3v2Tag() const;
|
|
bool hasAnyTag() const;
|
|
Id3v1Tag *id3v1Tag() const;
|
|
const std::vector<std::unique_ptr<Id3v2Tag> > &id3v2Tags() const;
|
|
void tags(std::vector<Tag *> &tags) const;
|
|
std::vector<Tag *> tags() const;
|
|
Mp4Tag *mp4Tag() const;
|
|
const std::vector<std::unique_ptr<MatroskaTag> > &matroskaTags() const;
|
|
bool areTagsSupported() const;
|
|
|
|
// methods to create/remove tags
|
|
bool createAppropriateTags(bool treatUnknownFilesAsMp3Files = false, TagUsage id3v1usage = TagUsage::KeepExisting,
|
|
TagUsage id3v2usage = TagUsage::Always, bool mergeMultipleSuccessiveId3v2Tags = true,
|
|
bool keepExistingId3v2version = true, uint32 id3v2version = 3, const std::vector<TagTarget> &requiredTargets = std::vector<TagTarget>());
|
|
bool removeId3v1Tag();
|
|
Id3v1Tag *createId3v1Tag();
|
|
bool removeId3v2Tag(Id3v2Tag *tag);
|
|
bool removeAllId3v2Tags();
|
|
Id3v2Tag *createId3v2Tag();
|
|
void removeTag(Tag *tag);
|
|
void removeAllTags();
|
|
void mergeId3v2Tags();
|
|
|
|
// methods to get/wipe notifications
|
|
bool haveRelatedObjectsNotifications() const;
|
|
NotificationType worstNotificationTypeIncludingRelatedObjects() const;
|
|
void gatherRelatedNotifications(NotificationList ¬ifications) const;
|
|
NotificationList gatherRelatedNotifications() const;
|
|
void clearParsingResults();
|
|
|
|
// methods to get, set object behaviour
|
|
bool isForcingFullParse() const;
|
|
void setForceFullParse(bool forceFullParse);
|
|
|
|
protected:
|
|
virtual void invalidated();
|
|
|
|
private:
|
|
// private methods internally used when rewriting the file to apply new tag information
|
|
// currently only the makeMp3File() methods is present; corresponding methods for
|
|
// other formats are outsourced to container classes
|
|
void makeMp3File();
|
|
// fields related to the container
|
|
ParsingStatus m_containerParsingStatus;
|
|
ContainerFormat m_containerFormat;
|
|
std::streamoff m_containerOffset;
|
|
uint64 m_paddingSize;
|
|
bool m_actualExistingId3v1Tag;
|
|
std::list<std::streamoff> m_actualId3v2TagOffsets;
|
|
std::unique_ptr<AbstractContainer> m_container;
|
|
// fields related to the tracks
|
|
ParsingStatus m_tracksParsingStatus;
|
|
std::unique_ptr<AbstractTrack> m_singleTrack;
|
|
// fields related to the tag
|
|
ParsingStatus m_tagsParsingStatus;
|
|
std::unique_ptr<Id3v1Tag> m_id3v1Tag;
|
|
std::vector<std::unique_ptr<Id3v2Tag> > m_id3v2Tags;
|
|
// fields related to the chapters and the attachments
|
|
ParsingStatus m_chaptersParsingStatus;
|
|
ParsingStatus m_attachmentsParsingStatus;
|
|
// fields specifying object behaviour
|
|
bool m_forceFullParse;
|
|
};
|
|
|
|
/*!
|
|
* \brief Returns an indication whether the container format has been parsed yet.
|
|
*/
|
|
inline ParsingStatus MediaFileInfo::containerParsingStatus() const
|
|
{
|
|
return m_containerParsingStatus;
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns the container format of the current file.
|
|
*
|
|
* parseContainerFormat() needs to be called before. Otherwise
|
|
* always ContainerFormat::Unknown will be returned.
|
|
*/
|
|
inline ContainerFormat MediaFileInfo::containerFormat() const
|
|
{
|
|
return m_containerFormat;
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns the name of the container format as C-style string.
|
|
*
|
|
* parseContainerFormat() needs to be called before. Otherwise
|
|
* always the name "Unknown" will be returned.
|
|
*
|
|
* \sa containerFormat()
|
|
* \sa containerFormatAbbreviation()
|
|
* \sa parseContainerFormat()
|
|
*/
|
|
inline const char *MediaFileInfo::containerFormatName() const
|
|
{
|
|
return Media::containerFormatName(m_containerFormat);
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns the subversion of the container format as C-style string.
|
|
*
|
|
* parseContainerFormat() needs to be called before. Otherwise
|
|
* always an empty string will be returned.
|
|
*
|
|
* \sa containerFormat()
|
|
* \sa containerFormatName()
|
|
* \sa parseContainerFormat()
|
|
*/
|
|
inline const char *MediaFileInfo::containerFormatSubversion() const
|
|
{
|
|
return Media::containerFormatSubversion(m_containerFormat);
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns the actual container start offset.
|
|
*/
|
|
inline uint64 MediaFileInfo::containerOffset() const
|
|
{
|
|
return m_containerOffset;
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns the padding size. Container format and tags should have been parsed yet.
|
|
*/
|
|
inline uint64 MediaFileInfo::paddingSize() const
|
|
{
|
|
return m_paddingSize;
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns an indication whether tag information has been parsed yet.
|
|
*/
|
|
inline ParsingStatus MediaFileInfo::tagsParsingStatus() const
|
|
{
|
|
return m_tagsParsingStatus;
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns an indication whether tracks have been parsed yet.
|
|
*/
|
|
inline ParsingStatus MediaFileInfo::tracksParsingStatus() const
|
|
{
|
|
return m_tracksParsingStatus;
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns the number of tracks that could be parsed.
|
|
*
|
|
* parseTracks() needs to be called before. Otherwise this
|
|
* method always returns zero.
|
|
*
|
|
* \sa parseTracks()
|
|
*/
|
|
inline size_t MediaFileInfo::trackCount() const
|
|
{
|
|
return m_singleTrack ? 1 : 0 + m_container->trackCount();
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns whether the chapters have been parsed yet.
|
|
*/
|
|
inline ParsingStatus MediaFileInfo::chaptersParsingStatus() const
|
|
{
|
|
return m_chaptersParsingStatus;
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns whether the attachments have been parsed yet.
|
|
*/
|
|
inline ParsingStatus MediaFileInfo::attachmentsParsingStatus() const
|
|
{
|
|
return m_attachmentsParsingStatus;
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns an indication whether an ID3v1 tag is assigned.
|
|
*/
|
|
inline bool MediaFileInfo::hasId3v1Tag() const
|
|
{
|
|
return m_id3v1Tag != nullptr;
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns an indication whether an ID3v2 tag is assigned.
|
|
*/
|
|
inline bool MediaFileInfo::hasId3v2Tag() const
|
|
{
|
|
return m_id3v2Tags.size();
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns an indication whether a tag of any format is assigned.
|
|
*/
|
|
inline bool MediaFileInfo::hasAnyTag() const
|
|
{
|
|
return hasId3v1Tag() || hasId3v2Tag() || (m_container && m_container->tagCount());
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns a pointer to the assigned ID3v1 tag or nullptr if none is assigned.
|
|
*
|
|
* \remarks The MediaFileInfo keeps the ownership over the returned
|
|
* pointer. The returned ID3v1 tag will be destroyed when the
|
|
* MediaFileInfo gets invalidated.
|
|
*/
|
|
inline Id3v1Tag *MediaFileInfo::id3v1Tag() const
|
|
{
|
|
return m_id3v1Tag.get();
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns pointers to the assigned ID3v2 tags.
|
|
*
|
|
* \remarks The MediaFileInfo keeps the ownership over the returned
|
|
* pointers. The returned ID3v2 tags will be destroyed when the
|
|
* MediaFileInfo gets invalidated.
|
|
*/
|
|
inline const std::vector<std::unique_ptr<Id3v2Tag> > &MediaFileInfo::id3v2Tags() const
|
|
{
|
|
return m_id3v2Tags;
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns the container for the current file.
|
|
*
|
|
* If there is not corresponding subclass of AbstractContainer for the
|
|
* container format or the container has not been parsed yet using
|
|
* the parseContainerFormat() method nullptr will be returned.
|
|
*
|
|
* \sa parseContainerFormat()
|
|
* \sa AbstractContainer
|
|
*/
|
|
inline AbstractContainer *MediaFileInfo::container() const
|
|
{
|
|
return m_container.get();
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns an indication whether forcing a full parse is enabled.
|
|
*
|
|
* If enabled the parser will analyse the file structure as deep as possible.
|
|
* This might cause long parsing times for big files.
|
|
*
|
|
* \sa setForceFullParse()
|
|
*/
|
|
inline bool MediaFileInfo::isForcingFullParse() const
|
|
{
|
|
return m_forceFullParse;
|
|
}
|
|
|
|
/*!
|
|
* \brief Sets whether forcing a full parse is enabled.
|
|
* \remarks The setting is applied next time parsing. The current parsing results are not mutated.
|
|
* \sa isForcingFullParse()
|
|
*/
|
|
inline void MediaFileInfo::setForceFullParse(bool forceFullParse)
|
|
{
|
|
m_forceFullParse = forceFullParse;
|
|
}
|
|
|
|
}
|
|
|
|
#endif // MEDIAINFO_H
|