From 817a8e25e6c91968363b8b76f93031e3aee44c4f Mon Sep 17 00:00:00 2001 From: Martchus Date: Thu, 4 Aug 2016 00:16:19 +0200 Subject: [PATCH] Improve documentation and consistency --- CMakeLists.txt | 1 - README.md | 12 ++-- abstractattachment.cpp | 17 ++++++ abstractattachment.h | 19 +++---- avc/avcconfiguration.cpp | 10 ++++ avc/avcconfiguration.h | 3 + avc/avcinfo.cpp | 15 +++++ avc/avcinfo.h | 6 +- fieldbasedtag.h | 91 ++++++++++++++++++++++--------- id3/id3v2tag.cpp | 7 +++ matroska/matroskaattachment.cpp | 10 +--- matroska/matroskachapter.cpp | 5 ++ matroska/matroskacontainer.cpp | 30 +++++----- matroska/matroskacues.cpp | 18 +++++- matroska/matroskaeditionentry.cpp | 12 ++-- mediafileinfo.cpp | 66 ++++++++-------------- mp4/mp4tag.cpp | 7 +++ mp4/mp4track.cpp | 22 +++++++- nestingsupportingtag.h | 64 ---------------------- ogg/oggcontainer.cpp | 17 +++--- tag.cpp | 66 ++++++++++++++++------ tag.h | 2 + tagvalue.cpp | 4 +- tagvalue.h | 12 ++-- 24 files changed, 295 insertions(+), 221 deletions(-) delete mode 100644 nestingsupportingtag.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9cbb854..8b98ab6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,6 @@ set(HEADER_FILES caseinsensitivecomparer.h mpegaudio/mpegaudioframe.h mpegaudio/mpegaudioframestream.h - nestingsupportingtag.h notification.h ogg/oggcontainer.h ogg/oggiterator.h diff --git a/README.md b/README.md index 914bc46..b9882b3 100644 --- a/README.md +++ b/README.md @@ -34,18 +34,15 @@ duration, size, timestamps, sampling frequency, FPS and other information of the It also allows to inspect and validate the element structure of MP4 and Matroska files. ## Text encoding, Unicode support -The library does not do any conversions for you (eg. converting Latin1 to UTF-8). However the -API provides a way to check which encoding is present (when reading) and which encoding(s) -can be used (when writing). +The library is aware of different text encodings and can convert between different encodings using iconv. ## Usage -For examples check out the command line interface of my [Tag Editor](https://github.com/Martchus/tageditor). +For examples check out the command line interface of [Tag Editor](https://github.com/Martchus/tageditor). ## Bugs, stability - Matroska files composed of more than one segment aren't tested yet and might not work. -- To add new features I've had to revise a lot of code since the last release. I always test the library with - files produced by mkvmerge and ffmpeg and several other file but can't verify that it will work with all - files. Hence I recommend you to create backups of your files. +- It is recommend you to create backups before editing because I can not test whether the + library works with all kind of files. ## Build instructions The tagparser library depends on c++utilities and is built in the same way. @@ -53,5 +50,4 @@ It also depends on zlib. ## TODO - Support more formats (EXIF, PDF metadata, Theora, ...). -- Allow adding tags to specific streams when dealing with OGG. - Do tests with Matroska files which have multiple segments. diff --git a/abstractattachment.cpp b/abstractattachment.cpp index ea7d661..a00a7e4 100644 --- a/abstractattachment.cpp +++ b/abstractattachment.cpp @@ -5,10 +5,12 @@ #include #include +#include #include using namespace std; +using namespace IoUtilities; namespace Media { @@ -63,6 +65,21 @@ void StreamDataBlock::makeBuffer() const stream().read(m_buffer.get(), size()); } +/*! + * \brief Copies the data to the specified \a stream. + * \remarks Makes use of the buffer allocated with makeBuffer() if this method has been called before. + */ +void StreamDataBlock::copyTo(ostream &stream) const +{ + if(buffer()) { + stream.write(buffer().get(), size()); + } else { + CopyHelper<0x2000> copyHelper; + m_stream().seekg(startOffset()); + copyHelper.copy(m_stream(), stream, size()); + } +} + /*! * \class Media::FileDataBlock * \brief The FileDataBlock class is a reference to a certain data block of a file stream. diff --git a/abstractattachment.h b/abstractattachment.h index 5defdd5..2b72a26 100644 --- a/abstractattachment.h +++ b/abstractattachment.h @@ -27,6 +27,7 @@ public: const std::unique_ptr &buffer() const; void makeBuffer() const; void discardBuffer(); + void copyTo(std::ostream &stream) const; protected: StreamDataBlock(); @@ -211,12 +212,10 @@ inline void AbstractAttachment::setId(const uint64 &id) /*! * \brief Returns a reference to the data of the attachment. - * - * The reference might be nullptr if there is no data assigned. - * The attachment keeps ownership over the reference. - * - * \sa setData() - * \sa setFile() + * \remarks + * - The reference might be nullptr if there is no data assigned. + * - The attachment keeps ownership over the reference. + * \sa setData(), setFile() */ inline const StreamDataBlock *AbstractAttachment::data() const { @@ -225,11 +224,8 @@ inline const StreamDataBlock *AbstractAttachment::data() const /*! * \brief Sets the \a data for the attachment. - * - * The specified \a data is moved to the attachment. - * - * \sa data() - * \sa setFile() + * \remarks The specified \a data is moved to the attachment. + * \sa data(), setFile() */ inline void AbstractAttachment::setData(std::unique_ptr &&data) { @@ -249,7 +245,6 @@ inline bool AbstractAttachment::isDataFromFile() const * \brief Returns whether the attachment is ignored/omitted when rewriting the container. * * The default value is false. - * * \sa setIgnored() */ inline bool AbstractAttachment::isIgnored() const diff --git a/avc/avcconfiguration.cpp b/avc/avcconfiguration.cpp index 9a6d491..b31e3c6 100644 --- a/avc/avcconfiguration.cpp +++ b/avc/avcconfiguration.cpp @@ -10,6 +10,16 @@ using namespace IoUtilities; namespace Media { +/*! + * \class AvcConfiguration + * \brief The AvcConfiguration struct provides a parser for AVC configuration. + */ + +/*! + * \brief Parses the AVC configuration using the specified \a reader. + * \throws Throws TruncatedDataException() when the config size exceeds the specified \a maxSize. + * \remarks Logging/reporting parsing errors is not implemented yet. + */ void AvcConfiguration::parse(BinaryReader &reader, uint64 maxSize) { if(maxSize < 7) { diff --git a/avc/avcconfiguration.h b/avc/avcconfiguration.h index 61b5f4f..72d4ff0 100644 --- a/avc/avcconfiguration.h +++ b/avc/avcconfiguration.h @@ -22,6 +22,9 @@ struct LIB_EXPORT AvcConfiguration void parse(IoUtilities::BinaryReader &reader, uint64 maxSize); }; +/*! + * \brief Constructs an empty AVC configuration. + */ inline AvcConfiguration::AvcConfiguration() : profileIndication(0), profileCompat(0), diff --git a/avc/avcinfo.cpp b/avc/avcinfo.cpp index 8be63ba..d0467ea 100644 --- a/avc/avcinfo.cpp +++ b/avc/avcinfo.cpp @@ -273,6 +273,21 @@ void HrdParameters::parse(IoUtilities::BitReader &reader) timeOffsetLength = reader.readBits(5); } +/*! + * \struct Media::TimingInfo + * \brief The TimingInfo struct holds timing information (part of SPS info). + */ +/*! + * \struct Media::SliceInfo + * \brief The SliceInfo struct holds the slice information of an AVC frame. + * \remarks currently not useful, might be removed + */ + +/*! + * \struct Media::AvcFrame + * \brief The AvcFrame struct holds an AVC frame. + * \remarks currently not useful, might be removed + */ } diff --git a/avc/avcinfo.h b/avc/avcinfo.h index 9a2d8a4..c04e361 100644 --- a/avc/avcinfo.h +++ b/avc/avcinfo.h @@ -115,7 +115,7 @@ inline SpsInfo::SpsInfo() : size(0) {} -struct PpsInfo { +struct LIB_EXPORT PpsInfo { PpsInfo(); ugolomb id; ugolomb spsId; @@ -132,7 +132,7 @@ inline PpsInfo::PpsInfo() : size(0) {} -struct SliceInfo { +struct LIB_EXPORT SliceInfo { SliceInfo(); byte naluType; byte naluRefIdc; @@ -167,7 +167,7 @@ inline SliceInfo::SliceInfo() : pps(0) {} -class AvcFrame { +class LIB_EXPORT AvcFrame { AvcFrame(); private: diff --git a/fieldbasedtag.h b/fieldbasedtag.h index 9d1a95f..baf8539 100644 --- a/fieldbasedtag.h +++ b/fieldbasedtag.h @@ -5,6 +5,7 @@ #include #include +#include namespace Media { @@ -27,11 +28,14 @@ class FieldMapBasedTag : public Tag public: FieldMapBasedTag(); - virtual const TagValue &value(KnownField field) const; virtual const TagValue &value(const typename FieldType::identifierType &id) const; + virtual const TagValue &value(KnownField field) const; virtual std::list values(const typename FieldType::identifierType &id) const; - virtual bool setValue(KnownField field, const TagValue &value); + virtual std::list values(KnownField field) const; virtual bool setValue(const typename FieldType::identifierType &id, const TagValue &value); + virtual bool setValue(KnownField field, const TagValue &value); + virtual bool setValues(const typename FieldType::identifierType &id, std::initializer_list values); + virtual bool setValues(KnownField field, std::initializer_list values); virtual bool hasField(KnownField field) const; virtual bool hasField(const typename FieldType::identifierType &id) const; virtual void removeAllFields(); @@ -72,14 +76,9 @@ template FieldMapBasedTag::FieldMapBasedTag() {} -template -inline const TagValue &FieldMapBasedTag::value(KnownField field) const -{ - return value(fieldId(field)); -} - /*! * \brief Returns the value of the field with the specified \a id. + * \sa Tag::value() */ template inline const TagValue &FieldMapBasedTag::value(const typename FieldType::identifierType &id) const @@ -88,11 +87,15 @@ inline const TagValue &FieldMapBasedTag::value(const typenam return i != m_fields.end() ? i->second.value() : TagValue::empty(); } +template +inline const TagValue &FieldMapBasedTag::value(KnownField field) const +{ + return value(fieldId(field)); +} + /*! * \brief Returns the values of the field with the specified \a id. - * - * There might me more then one value assigned to a \a field. Whereas value() - * returns only the first value, this method returns all values. + * \sa Tag::values() */ template inline std::list FieldMapBasedTag::values(const typename FieldType::identifierType &id) const @@ -100,11 +103,19 @@ inline std::list FieldMapBasedTag::values( auto range = m_fields.equal_range(id); std::list values; for(auto i = range.first; i != range.second; ++i) { - values.push_back(&i->second.value()); + if(!i->second.value().isEmpty()) { + values.push_back(&i->second.value()); + } } return values; } +template +inline std::list FieldMapBasedTag::values(KnownField field) const +{ + return values(fieldId(field)); +} + template inline bool FieldMapBasedTag::setValue(KnownField field, const TagValue &value) { @@ -113,6 +124,7 @@ inline bool FieldMapBasedTag::setValue(KnownField field, con /*! * \brief Assigns the given \a value to the field with the specified \a id. + * \sa Tag::setValue() */ template bool FieldMapBasedTag::setValue(const typename FieldType::identifierType &id, const Media::TagValue &value) @@ -120,14 +132,49 @@ bool FieldMapBasedTag::setValue(const typename FieldType::id auto i = m_fields.find(id); if(i != m_fields.end()) { // field already exists -> set its value i->second.setValue(value); - } else if(!value.isEmpty()) {// field doesn't exist -> create new one if value is not null - m_fields.insert(std::pair(id, FieldType(id, value))); + } else if(!value.isEmpty()) { // field doesn't exist -> create new one if value is not null + m_fields.insert(std::make_pair(id, FieldType(id, value))); } else { // otherwise return false return false; } return true; } +/*! + * \brief Assigns the given \a values to the field with the specified \a id. + * \sa Tag::setValues() + */ +template +bool FieldMapBasedTag::setValues(const typename FieldType::identifierType &id, std::initializer_list values) +{ + auto valuesIterator = values.begin(); + auto range = m_fields.equal_range(id); + for(; valuesIterator != values.end() && range.first != range.second; ++valuesIterator) { + if(!valuesIterator->isEmpty()) { + range.first->second.setValue(*valuesIterator); + ++range.first; + } + } + for(; valuesIterator != values.end(); ++valuesIterator) { + m_fields.insert(std::make_pair(id, FieldType(id, *valuesIterator))); + } + for(; range.first != range.second; ++range.first) { + range.first->second.setValue(TagValue()); + } + return true; +} + +/*! + * \brief Assigns the given \a values to the field with the specified \a id. + * \remarks There might me more then one value assigned to a \a field. Whereas setValue() only alters the first value, this + * method will replace all currently assigned values with the specified \a values. + */ +template +bool FieldMapBasedTag::setValues(KnownField field, std::initializer_list values) +{ + return setValues(fieldId(field), values); +} + template inline bool FieldMapBasedTag::hasField(KnownField field) const { @@ -150,11 +197,7 @@ inline void FieldMapBasedTag::removeAllFields() } /*! - * \brief Returns the fields of the tag. - * - * This method provides direct access to the fields of the tag. It might - * be usefull when the convenience methods value(), setValue(), hasField(), ... - * do not offer the required functionality. + * \brief Returns the fields of the tag by providing direct access to the field map of the tag. */ template inline const std::multimap &FieldMapBasedTag::fields() const @@ -163,11 +206,7 @@ inline const std::multimap inline std::multimap &FieldMapBasedTag::fields() @@ -178,7 +217,7 @@ inline std::multimap &Fi template unsigned int FieldMapBasedTag::fieldCount() const { - int count = 0; + unsigned int count = 0; for(const auto &field : m_fields) { if(!field.second.value().isEmpty()) { ++count; @@ -233,7 +272,7 @@ int FieldMapBasedTag::insertFields(const FieldMapBasedTag(fromField.id(), fromField)); + fields().insert(std::make_pair(fromField.id(), fromField)); ++fieldsInserted; } } diff --git a/id3/id3v2tag.cpp b/id3/id3v2tag.cpp index 8085121..a54664b 100644 --- a/id3/id3v2tag.cpp +++ b/id3/id3v2tag.cpp @@ -379,6 +379,13 @@ bool FrameComparer::operator()(const uint32 &lhs, const uint32 &rhs) const return lhs < rhs; } +/*! + * \class Media::Id3v2TagMaker + * \brief The Id3v2TagMaker class helps writing ID3v2 tags. + * + * An instance can be obtained using the Id3v2Tag::prepareMaking() method. + */ + /*! * \brief Prepares making the specified \a tag. * \sa See Id3v2Tag::prepareMaking() for more information. diff --git a/matroska/matroskaattachment.cpp b/matroska/matroskaattachment.cpp index 64956fe..5cdb68c 100644 --- a/matroska/matroskaattachment.cpp +++ b/matroska/matroskaattachment.cpp @@ -169,15 +169,7 @@ void MatroskaAttachmentMaker::make(ostream &stream) const stream.write(buff, 2); len = EbmlElement::makeSizeDenotation(attachment().data()->size(), buff); stream.write(buff, len); - // copy data - if(attachment().data()->buffer()) { - stream.write(attachment().data()->buffer().get(), attachment().data()->size()); - } else { - CopyHelper<0x2000> copyHelper; - attachment().data()->stream().seekg(attachment().data()->startOffset()); - copyHelper.copy(attachment().data()->stream(), stream, attachment().data()->size()); - } - + attachment().data()->copyTo(stream); } } diff --git a/matroska/matroskachapter.cpp b/matroska/matroskachapter.cpp index c952c97..abbb423 100644 --- a/matroska/matroskachapter.cpp +++ b/matroska/matroskachapter.cpp @@ -9,6 +9,11 @@ using namespace ChronoUtilities; namespace Media { +/*! + * \class MatroskaChapter + * \brief The MatroskaChapter class provides an implementation of AbstractAttachment for Matroska files. + */ + /*! * \brief Constructs a new MatroskaChapter for the specified \a chapterAtomElement. */ diff --git a/matroska/matroskacontainer.cpp b/matroska/matroskacontainer.cpp index f9e6d7e..3fd48c7 100644 --- a/matroska/matroskacontainer.cpp +++ b/matroska/matroskacontainer.cpp @@ -707,8 +707,10 @@ void MatroskaContainer::internalParseAttachments() } } +/// \brief The private SegmentData struct is used in MatroskaContainer::internalMakeFile() to store segment specific data. struct SegmentData { + /// \brief Constructs a new segment data object. SegmentData() : hasCrc32(false), cuesElement(nullptr), @@ -723,33 +725,33 @@ struct SegmentData newDataOffset(0) {} - // whether CRC-32 checksum is present + /// \brief whether CRC-32 checksum is present bool hasCrc32; - // used to make "SeekHead"-element + /// \brief used to make "SeekHead"-element MatroskaSeekInfo seekInfo; - // "Cues"-element (original file) + /// \brief "Cues"-element (original file) EbmlElement *cuesElement; - // used to make "Cues"-element + /// \brief used to make "Cues"-element MatroskaCuePositionUpdater cuesUpdater; - // size of the "SegmentInfo"-element + /// \brief size of the "SegmentInfo"-element uint64 infoDataSize; - // cluster sizes + /// \brief cluster sizes vector clusterSizes; - // first "Cluster"-element (original file) + /// \brief first "Cluster"-element (original file) EbmlElement *firstClusterElement; - // end offset of last "Cluster"-element (original file) + /// \brief end offset of last "Cluster"-element (original file) uint64 clusterEndOffset; - // start offset (in the new file) + /// \brief start offset (in the new file) uint64 startOffset; - // padding (in the new file) + /// \brief padding (in the new file) uint64 newPadding; - // header size (in the new file) + /// \brief header size (in the new file) byte sizeDenotationLength; - // total size of the segment data (in the new file, excluding header) + /// \brief total size of the segment data (in the new file, excluding header) uint64 totalDataSize; - // total size of the segment data (in the new file, including header) + /// \brief total size of the segment data (in the new file, including header) uint64 totalSize; - // data offset of the segment in the new file + /// \brief data offset of the segment in the new file uint64 newDataOffset; }; diff --git a/matroska/matroskacues.cpp b/matroska/matroskacues.cpp index 1aa9f7d..8652df4 100644 --- a/matroska/matroskacues.cpp +++ b/matroska/matroskacues.cpp @@ -8,11 +8,27 @@ using namespace ConversionUtilities; namespace Media { +/*! + * \class MatroskaOffsetStates + * \brief The MatroskaOffsetStates holds an offset within a Matroska file. + * + * The purpose of this class is to preserve the previous value when an offset + * is updated. + */ + +/*! + * \class MatroskaReferenceOffsetPair + * \brief The MatroskaReferenceOffsetPair holds an offset within a Matroska file plus the reference offset. + * + * The purpose of this class is to preserve the previous value when an offset + * is updated. + */ + /*! * \class Media::MatroskaCuePositionUpdater * \brief The MatroskaCuePositionUpdater class helps to rewrite the "Cues"-element with shifted positions. * - * This class is used when rewriting Matroska files to save changed tag information. + * This class is used when rewriting a Matroska file to save changed tag information. */ /*! diff --git a/matroska/matroskaeditionentry.cpp b/matroska/matroskaeditionentry.cpp index adca42d..3bb11f6 100644 --- a/matroska/matroskaeditionentry.cpp +++ b/matroska/matroskaeditionentry.cpp @@ -10,6 +10,11 @@ using namespace std; namespace Media { +/*! + * \class MatroskaEditionEntry + * \brief The MatroskaEditionEntry class provides a parser for edition entries in Matroska files. + */ + /*! * \brief Constructs a new MatroskaEditionEntry for the specified \a editionEntryElement. */ @@ -79,10 +84,9 @@ void MatroskaEditionEntry::parse() /*! * \brief Parses the "EditionEntry"-element specified when constructing the object. - * - * Parses also fetched chapters and nested chapters. - * - * Clears all previous parsing results. + * \remarks + * - Parses also fetched chapters and nested chapters. + * - Clears all previous parsing results. */ void MatroskaEditionEntry::parseNested() { diff --git a/mediafileinfo.cpp b/mediafileinfo.cpp index 96a5440..67075ff 100644 --- a/mediafileinfo.cpp +++ b/mediafileinfo.cpp @@ -138,16 +138,10 @@ MediaFileInfo::~MediaFileInfo() * containerFormatAbbreviation(), containerFormatSubversion(), containerMimeType(), * container(), mp4Container() and matroskaContainer() will return the parsed * information. - * * \throws Throws std::ios_base::failure when an IO error occurs. * \throws Throws Media::Failure or a derived exception when a parsing * error occurs. - * - * \sa isContainerParsed() - * \sa parseTracks() - * \sa parseTag() - * \sa parseChapters() - * \sa parseEverything() + * \sa isContainerParsed(), parseTracks(), parseTag(), parseChapters(), parseEverything() */ void MediaFileInfo::parseContainerFormat() { @@ -290,25 +284,17 @@ startParsingSignature: * After calling this method the methods trackCount(), tracks(), and * hasTracksOfType() will return the parsed * information. - * * \throws Throws std::ios_base::failure when an IO error occurs. * \throws Throws Media::Failure or a derived exception when a parsing * error occurs. - * - * \remarks parseContainerFormat() is called before the tracks will be parsed. - * - * \sa areTracksParsed() - * \sa parseContainerFormat() - * \sa parseTag() - * \sa parseChapters() - * \sa parseEverything() + * \remarks parseContainerFormat() must be called before. + * \sa areTracksParsed(), parseContainerFormat(), parseTags(), parseChapters(), parseEverything() */ void MediaFileInfo::parseTracks() { if(tracksParsingStatus() != ParsingStatus::NotParsedYet) { // there's no need to read the tracks twice return; } - parseContainerFormat(); // ensure the container format has been load yet static const string context("parsing tracks"); try { if(m_container) { @@ -359,25 +345,17 @@ void MediaFileInfo::parseTracks() * mp4Tag() and allTags() will return the parsed information. * * Previously assigned but not applied tag information will be discarted. - * * \throws Throws std::ios_base::failure when an IO error occurs. * \throws Throws Media::Failure or a derived exception when a parsing * error occurs. - * - * \remarks parseContainerFormat() is called before the tags informations will be parsed. - * - * \sa isTagParsed() - * \sa parseContainerFormat() - * \sa parseTracks() - * \sa parseChapters() - * \sa parseEverything() + * \remarks parseContainerFormat() must be called before. + * \sa isTagParsed(), parseContainerFormat(), parseTracks(), parseChapters(), parseEverything() */ void MediaFileInfo::parseTags() { if(tagsParsingStatus() != ParsingStatus::NotParsedYet) { // there's no need to read the tags twice return; } - parseContainerFormat(); // ensure the container format has been load yet static const string context("parsing tag"); // check for id3v1 tag if(size() >= 128) { @@ -436,14 +414,8 @@ void MediaFileInfo::parseTags() * \throws Throws std::ios_base::failure when an IO error occurs. * \throws Throws Media::Failure or a derived exception when a parsing * error occurs. - * - * \remarks parseContainerFormat() is called before the tags informations will be parsed. - * - * \sa areChaptersParsed() - * \sa parseContainerFormat() - * \sa parseTracks() - * \sa parseTags() - * \sa parseEverything() + * \remarks parseContainerFormat() must be called before. + * \sa areChaptersParsed(), parseContainerFormat(), parseTracks(), parseTags(), parseEverything() */ void MediaFileInfo::parseChapters() { @@ -458,15 +430,26 @@ void MediaFileInfo::parseChapters() } else { throw NotImplementedException(); } - } catch (NotImplementedException &) { + } catch (const NotImplementedException &) { m_chaptersParsingStatus = ParsingStatus::NotSupported; addNotification(NotificationType::Information, "Parsing chapters is not implemented for the container format of the file.", context); - } catch (Failure &) { + } catch (const Failure &) { m_chaptersParsingStatus = ParsingStatus::CriticalFailure; addNotification(NotificationType::Critical, "Unable to parse chapters.", context); } } +/*! + * \brief Parses the attachments of the current file. + * + * This method parses the attachments of the current file if not been parsed yet. + * + * \throws Throws std::ios_base::failure when an IO error occurs. + * \throws Throws Media::Failure or a derived exception when a parsing + * error occurs. + * \remarks parseContainerFormat() must be called before. + * \sa areChaptersParsed(), parseContainerFormat(), parseTracks(), parseTags(), parseEverything() + */ void MediaFileInfo::parseAttachments() { if(attachmentsParsingStatus() != ParsingStatus::NotParsedYet) { // there's no need to read the attachments twice @@ -480,10 +463,10 @@ void MediaFileInfo::parseAttachments() } else { throw NotImplementedException(); } - } catch (NotImplementedException &) { + } catch (const NotImplementedException &) { m_attachmentsParsingStatus = ParsingStatus::NotSupported; addNotification(NotificationType::Information, "Parsing attachments is not implemented for the container format of the file.", context); - } catch (Failure &) { + } catch (const Failure &) { m_attachmentsParsingStatus = ParsingStatus::CriticalFailure; addNotification(NotificationType::Critical, "Unable to parse attachments.", context); } @@ -493,10 +476,7 @@ void MediaFileInfo::parseAttachments() * \brief Parses the container format, the tracks and the tag information of the current file. * * See the individual methods to for more details and exceptions which might be thrown. - * - * \sa parseContainerFormat(); - * \sa parseTracks(); - * \sa parseTag(); + * \sa parseContainerFormat(), parseTracks(), parseTags() */ void MediaFileInfo::parseEverything() { diff --git a/mp4/mp4tag.cpp b/mp4/mp4tag.cpp index 2b945bc..1e3fef7 100644 --- a/mp4/mp4tag.cpp +++ b/mp4/mp4tag.cpp @@ -255,6 +255,13 @@ void Mp4Tag::make(ostream &stream) prepareMaking().make(stream); } +/*! + * \class Media::Mp4TagMaker + * \brief The Mp4TagMaker class helps writing MP4 tags. + * + * An instance can be obtained using the Mp4Tag::prepareMaking() method. + */ + /*! * \brief Prepares making the specified \a tag. * \sa See Mp4Tag::prepareMaking() for more information. diff --git a/mp4/mp4track.cpp b/mp4/mp4track.cpp index 50dbc97..41c1167 100644 --- a/mp4/mp4track.cpp +++ b/mp4/mp4track.cpp @@ -27,7 +27,14 @@ using namespace ChronoUtilities; namespace Media { -DateTime startDate = DateTime::fromDate(1904, 1, 1); +/// \brief Dates within MP4 tracks are expressed as the number of seconds since this date. +const DateTime startDate = DateTime::fromDate(1904, 1, 1); + +/*! + * \class Mpeg4AudioSpecificConfig + * \brief The Mpeg4AudioSpecificConfig class holds MPEG-4 audio specific config parsed using Mp4Track::parseAudioSpecificConfig(). + * \remarks Is part of Mpeg4ElementaryStreamInfo (audio streams only). + */ Mpeg4AudioSpecificConfig::Mpeg4AudioSpecificConfig() : audioObjectType(0), @@ -51,10 +58,23 @@ Mpeg4AudioSpecificConfig::Mpeg4AudioSpecificConfig() : epConfig(0) {} +/*! + * \class Mpeg4VideoSpecificConfig + * \brief The Mpeg4VideoSpecificConfig class holds MPEG-4 video specific config parsed using Mp4Track::parseVideoSpecificConfig(). + * \remarks + * - Is part of Mpeg4ElementaryStreamInfo (video streams only). + * - AVC configuration is another thing and covered by the AvcConfiguration class. + */ + Mpeg4VideoSpecificConfig::Mpeg4VideoSpecificConfig() : profile(0) {} +/*! + * \class Mpeg4ElementaryStreamInfo + * \brief The Mpeg4ElementaryStreamInfo class holds MPEG-4 elementary stream info parsed using Mp4Track::parseMpeg4ElementaryStreamInfo(). + */ + /*! * \class Media::Mp4Track * \brief Implementation of Media::AbstractTrack for the MP4 container. diff --git a/nestingsupportingtag.h b/nestingsupportingtag.h deleted file mode 100644 index 02b3ff6..0000000 --- a/nestingsupportingtag.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef NESTEDTAGSUPPORT -#define NESTEDTAGSUPPORT - -#include "tag.h" - -namespace Media { - -template -class LIB_EXPORT NestingSupportingTag : public Tag -{ -public: - NestingSupportingTag(); - - const std::vector &nestedTags() const; - TagType *parent() const; - bool setParent(Tag *tag); - virtual TagType *nestedTag(size_t index) const; - virtual size_t nestedTagCount() const; - //const std::vector nestedTags() const; - virtual bool supportsNestedTags() const; - -private: - std::vector m_nestedTags; - TagType *m_parent; -}; - -inline const std::vector &NestingSupportingTag::nestedTags() const -{ - return m_nestedTags; -} - -inline TagType *NestingSupportingTag::parent() const -{ - return m_parent; -} - -bool NestingSupportingTag::setParent(Tag *tag) -{ - if(m_parent != tag) { - if() { - - } - } -} - -inline TagType *NestingSupportingTag::nestedTag(size_t index) const -{ - return m_nestedTags.at(index); -} - -inline size_t NestingSupportingTag::nestedTagCount() const -{ - return m_nestedTags.size(); -} - -inline bool NestingSupportingTag::supportsNestedTags() const -{ - return true; -} - -} - -#endif // NESTEDTAGSUPPORT - diff --git a/ogg/oggcontainer.cpp b/ogg/oggcontainer.cpp index ef0801c..cb5d68f 100644 --- a/ogg/oggcontainer.cpp +++ b/ogg/oggcontainer.cpp @@ -60,12 +60,10 @@ void OggContainer::reset() * \sa AbstractContainer::createTag() * \remarks * - Tracks must be parsed before because tags are stored on track level! - * - The track can be specified via the \a target argument. However, only the first track of tracks() array is considered. - * - If tracks() array of \a target is empty, a random track will be picked. - * - Vorbis streams should always have a tag assigned yet. However, this - * methods allows creation of a tag if none has been assigned yet. - * - FLAC streams should always have a tag assigned yet and this method - * does NOT allow to create a tag in this case. + * - The track can be specified via the \a target argument. However, only the first track of tracks() array of \a target is considered. + * - If tracks() array of \a target is empty, the first track/tag is picked. + * - Vorbis streams should always have a tag assigned; this method allows creation of a tag for Vorbis streams if none is present though. + * - FLAC streams should always have a tag assigned; this method does *not* allow creation of a tag for FLAC streams if none is present though. */ OggVorbisComment *OggContainer::createTag(const TagTarget &target) { @@ -145,12 +143,11 @@ size_t OggContainer::tagCount() const /*! * \brief Actually just flags the specified \a tag as removed and clears all assigned fields. * - * This specialization is neccessary because completeley removing the tag whould also - * remove the OGG parameter which are needed when appying the changes. + * This specialization is neccessary because removing the tag completely whould also + * remove the OGG parameter which are needed when appying changes. * * \remarks Seems like common players aren't able to play Vorbis when no comment is present. - * So do NOT use this method to remove tags from Vorbis, just call removeAllFields() on \a tag. - * \sa AbstractContainer::removeTag() + * So do NOT use this method to remove tags from Vorbis, just call Tag::removeAllFields() on \a tag. */ bool OggContainer::removeTag(Tag *tag) { diff --git a/tag.cpp b/tag.cpp index 44f0d19..9880a62 100644 --- a/tag.cpp +++ b/tag.cpp @@ -33,41 +33,71 @@ Tag::~Tag() */ string Tag::toString() const { - stringstream ss; - ss << typeName(); - if(supportsTarget() && !target().isEmpty()) { - ss << " targeting " << targetString(); + string res; + res += typeName(); + if(supportsTarget()) { + res += " targeting "; + res += targetString(); } - return ss.str(); + return res; +} + +/*! + * \brief Returns the values of the specified \a field. + * \remarks + * - There might me more than one value assigned to a \a field. Whereas value() + * returns only the first value, this method returns all values. + * - However, the default implementation just returns the first value assuming + * multiple values per field are not supported by the tag. + */ +std::list Tag::values(KnownField field) const +{ + std::list values; + const TagValue &v = value(field); + if(!v.isEmpty()) { + values.push_back(&v); + } + return values; +} + +/*! + * \brief Assigns the given \a values to the specified \a field. + * \remarks + * - There might me more then one value assigned to a \a field. Whereas setValue() only alters the first value, this + * method will replace all currently assigned values with the specified \a values. + * - However, the default implementation just sets the first value and discards additional values assuming + * multiple values per field are not supported by the tag. + */ +bool Tag::setValues(KnownField field, std::initializer_list values) +{ + return setValue(field, values.size() ? *values.begin() : TagValue()); } /*! * \fn Tag::value() * \brief Returns the value of the specified \a field. - * - * If no value for the specified \a field is assigned an - * empty TagValue will be returned. - * - * \sa setValue() - * \sa hasField() + * \remarks + * - If the specified \a field is not present an empty TagValue will be returned. + * - Some tags support more than just one value per field. If there are multiple values + * this method just returns the first one. + * \sa setValue(), hasField() */ /*! * \fn Tag::setValue() * \brief Assigns the given \a value to the specified \a field. - * - * If an empty \a value is given, the field will be be removed. - * - * \sa value() - * \sa hasField() + * \remarks + * - If an empty \a value is given, the field will be be removed. + * - Some tags support more than just one value per field. This method will only + * alter the first value. + * \sa value(), hasField() */ /*! * \fn Tag::hasField() * \brief Returns an indication whether the specified \a field is present. * - * \sa value() - * \sa setValue() + * \sa value(), setValue() */ /*! diff --git a/tag.h b/tag.h index 298bd8b..965f731 100644 --- a/tag.h +++ b/tag.h @@ -107,7 +107,9 @@ public: virtual TagTextEncoding proposedTextEncoding() const; virtual bool canEncodingBeUsed(TagTextEncoding encoding) const; virtual const TagValue &value(KnownField field) const = 0; + virtual std::list values(KnownField field) const; virtual bool setValue(KnownField field, const TagValue &value) = 0; + virtual bool setValues(KnownField field, std::initializer_list values); virtual bool hasField(KnownField field) const = 0; virtual void removeAllFields() = 0; const std::string &version() const; diff --git a/tagvalue.cpp b/tagvalue.cpp index 5d7efd2..ce39e80 100644 --- a/tagvalue.cpp +++ b/tagvalue.cpp @@ -329,6 +329,7 @@ pair encodingParameter(TagTextEncoding tagTextEncoding) /*! * \brief Converts the value of the current TagValue object to its equivalent * std::string representation. + * \param result Specifies the string to store the result. * \param encoding Specifies the encoding to to be used; set to TagTextEncoding::Unspecified to use the * present encoding without any character set conversion. * \remarks If UTF-16 is the desired output \a encoding, it makes sense to use the toWString() method instead. @@ -404,7 +405,8 @@ void TagValue::toString(string &result, TagTextEncoding encoding) const * \brief Converts the value of the current TagValue object to its equivalent * std::u16string representation. * \throws Throws ConversionException on failure. - * \remarks Use this only, if UTF-16 text is assigned. + * \remarks Use this only, if \a encoding is an UTF-16 encoding. + * \sa toString() */ void TagValue::toWString(std::u16string &result, TagTextEncoding encoding) const { diff --git a/tagvalue.h b/tagvalue.h index de20199..9ac9db7 100644 --- a/tagvalue.h +++ b/tagvalue.h @@ -301,7 +301,7 @@ inline std::string TagValue::toString(TagTextEncoding encoding) const * \brief Converts the value of the current TagValue object to its equivalent * std::wstring representation. * \throws Throws ConversionException on failure. - * \remarks Use this only, if UTF-16 text is assigned. + * \remarks Use this only, if \a encoding is an UTF-16 encoding. */ inline std::u16string TagValue::toWString(TagTextEncoding encoding) const { @@ -312,7 +312,7 @@ inline std::u16string TagValue::toWString(TagTextEncoding encoding) const /*! * \brief Returns an indication whether an value is assigned. - * \remarks Meta data such as description and mime type is not considered as an assigned value. + * \remarks Meta data such as description and MIME type is not considered as an assigned value. */ inline bool TagValue::isEmpty() const { @@ -321,7 +321,7 @@ inline bool TagValue::isEmpty() const /*! * \brief Clears the assigned data. - * \remarks Meta data such as description and mime type remains unaffected. + * \remarks Meta data such as description and MIME type remains unaffected. * \sa clearMetadata() * \sa clearDataAndMetadata() */ @@ -333,7 +333,7 @@ inline void TagValue::clearData() /*! * \brief Returns the size of the assigned value in bytes. - * \remarks Meta data such as description and mime type is not considered as part of the assigned value. + * \remarks Meta data such as description and MIME type is not considered as part of the assigned value. */ inline size_t TagValue::dataSize() const { @@ -377,7 +377,7 @@ inline void TagValue::setDescription(const std::string &value, TagTextEncoding e } /*! - * \brief Returns the mime type. + * \brief Returns the MIME type. * \remarks The usage of this meta information depends on the tag implementation. * \sa setMimeType() */ @@ -387,7 +387,7 @@ inline const std::string &TagValue::mimeType() const } /*! - * \brief Sets the mime type. + * \brief Sets the MIME type. * \param value Specifies the mime type. * \remarks The usage of this meta information depends on the tag implementation. * \sa mimeType()