Improve documentation and consistency

This commit is contained in:
Martchus 2016-08-04 00:16:19 +02:00
parent 8663dedf8c
commit 817a8e25e6
24 changed files with 295 additions and 221 deletions

View File

@ -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

View File

@ -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.

View File

@ -5,10 +5,12 @@
#include <c++utilities/misc/memory.h>
#include <c++utilities/io/catchiofailure.h>
#include <c++utilities/io/copy.h>
#include <sstream>
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.

View File

@ -27,6 +27,7 @@ public:
const std::unique_ptr<char[]> &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<StreamDataBlock> &&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

View File

@ -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) {

View File

@ -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),

View File

@ -273,6 +273,21 @@ void HrdParameters::parse(IoUtilities::BitReader &reader)
timeOffsetLength = reader.readBits<byte>(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
*/
}

View File

@ -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:

View File

@ -5,6 +5,7 @@
#include <map>
#include <functional>
#include <initializer_list>
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<const TagValue *> values(const typename FieldType::identifierType &id) const;
virtual bool setValue(KnownField field, const TagValue &value);
virtual std::list<const TagValue *> 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<TagValue> values);
virtual bool setValues(KnownField field, std::initializer_list<TagValue> values);
virtual bool hasField(KnownField field) const;
virtual bool hasField(const typename FieldType::identifierType &id) const;
virtual void removeAllFields();
@ -72,14 +76,9 @@ template <class FieldType, class Compare>
FieldMapBasedTag<FieldType, Compare>::FieldMapBasedTag()
{}
template <class FieldType, class Compare>
inline const TagValue &FieldMapBasedTag<FieldType, Compare>::value(KnownField field) const
{
return value(fieldId(field));
}
/*!
* \brief Returns the value of the field with the specified \a id.
* \sa Tag::value()
*/
template <class FieldType, class Compare>
inline const TagValue &FieldMapBasedTag<FieldType, Compare>::value(const typename FieldType::identifierType &id) const
@ -88,11 +87,15 @@ inline const TagValue &FieldMapBasedTag<FieldType, Compare>::value(const typenam
return i != m_fields.end() ? i->second.value() : TagValue::empty();
}
template <class FieldType, class Compare>
inline const TagValue &FieldMapBasedTag<FieldType, Compare>::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 <class FieldType, class Compare>
inline std::list<const TagValue *> FieldMapBasedTag<FieldType, Compare>::values(const typename FieldType::identifierType &id) const
@ -100,11 +103,19 @@ inline std::list<const TagValue *> FieldMapBasedTag<FieldType, Compare>::values(
auto range = m_fields.equal_range(id);
std::list<const TagValue *> 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 <class FieldType, class Compare>
inline std::list<const TagValue *> FieldMapBasedTag<FieldType, Compare>::values(KnownField field) const
{
return values(fieldId(field));
}
template <class FieldType, class Compare>
inline bool FieldMapBasedTag<FieldType, Compare>::setValue(KnownField field, const TagValue &value)
{
@ -113,6 +124,7 @@ inline bool FieldMapBasedTag<FieldType, Compare>::setValue(KnownField field, con
/*!
* \brief Assigns the given \a value to the field with the specified \a id.
* \sa Tag::setValue()
*/
template <class FieldType, class Compare>
bool FieldMapBasedTag<FieldType, Compare>::setValue(const typename FieldType::identifierType &id, const Media::TagValue &value)
@ -120,14 +132,49 @@ bool FieldMapBasedTag<FieldType, Compare>::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<typename FieldType::identifierType, FieldType>(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 <class FieldType, class Compare>
bool FieldMapBasedTag<FieldType, Compare>::setValues(const typename FieldType::identifierType &id, std::initializer_list<TagValue> 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 <class FieldType, class Compare>
bool FieldMapBasedTag<FieldType, Compare>::setValues(KnownField field, std::initializer_list<TagValue> values)
{
return setValues(fieldId(field), values);
}
template <class FieldType, class Compare>
inline bool FieldMapBasedTag<FieldType, Compare>::hasField(KnownField field) const
{
@ -150,11 +197,7 @@ inline void FieldMapBasedTag<FieldType, Compare>::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 <class FieldType, class Compare>
inline const std::multimap<typename FieldType::identifierType, FieldType, Compare> &FieldMapBasedTag<FieldType, Compare>::fields() const
@ -163,11 +206,7 @@ inline const std::multimap<typename FieldType::identifierType, FieldType, Compar
}
/*!
* \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 <class FieldType, class Compare>
inline std::multimap<typename FieldType::identifierType, FieldType, Compare> &FieldMapBasedTag<FieldType, Compare>::fields()
@ -178,7 +217,7 @@ inline std::multimap<typename FieldType::identifierType, FieldType, Compare> &Fi
template <class FieldType, class Compare>
unsigned int FieldMapBasedTag<FieldType, Compare>::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<FieldType, Compare>::insertFields(const FieldMapBasedTag<Fi
}
}
if(!fieldInserted) {
fields().insert(std::pair<typename FieldType::identifierType, FieldType>(fromField.id(), fromField));
fields().insert(std::make_pair(fromField.id(), fromField));
++fieldsInserted;
}
}

View File

@ -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.

View File

@ -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);
}
}

View File

@ -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.
*/

View File

@ -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<uint64> 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;
};

View File

@ -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.
*/
/*!

View File

@ -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()
{

View File

@ -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()
{

View File

@ -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.

View File

@ -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.

View File

@ -1,64 +0,0 @@
#ifndef NESTEDTAGSUPPORT
#define NESTEDTAGSUPPORT
#include "tag.h"
namespace Media {
template <class TagType>
class LIB_EXPORT NestingSupportingTag : public Tag
{
public:
NestingSupportingTag();
const std::vector<TagType *> &nestedTags() const;
TagType *parent() const;
bool setParent(Tag *tag);
virtual TagType *nestedTag(size_t index) const;
virtual size_t nestedTagCount() const;
//const std::vector<Tag *> nestedTags() const;
virtual bool supportsNestedTags() const;
private:
std::vector<TagType *> m_nestedTags;
TagType *m_parent;
};
inline const std::vector<TagType *> &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

View File

@ -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)
{

66
tag.cpp
View File

@ -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<const TagValue *> Tag::values(KnownField field) const
{
std::list<const TagValue *> 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<TagValue> 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()
*/
/*!

2
tag.h
View File

@ -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<const TagValue *> values(KnownField field) const;
virtual bool setValue(KnownField field, const TagValue &value) = 0;
virtual bool setValues(KnownField field, std::initializer_list<TagValue> values);
virtual bool hasField(KnownField field) const = 0;
virtual void removeAllFields() = 0;
const std::string &version() const;

View File

@ -329,6 +329,7 @@ pair<const char *, float> 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
{

View File

@ -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()