Improve documentation and consistency
This commit is contained in:
parent
8663dedf8c
commit
817a8e25e6
|
@ -27,7 +27,6 @@ set(HEADER_FILES
|
||||||
caseinsensitivecomparer.h
|
caseinsensitivecomparer.h
|
||||||
mpegaudio/mpegaudioframe.h
|
mpegaudio/mpegaudioframe.h
|
||||||
mpegaudio/mpegaudioframestream.h
|
mpegaudio/mpegaudioframestream.h
|
||||||
nestingsupportingtag.h
|
|
||||||
notification.h
|
notification.h
|
||||||
ogg/oggcontainer.h
|
ogg/oggcontainer.h
|
||||||
ogg/oggiterator.h
|
ogg/oggiterator.h
|
||||||
|
|
12
README.md
12
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.
|
It also allows to inspect and validate the element structure of MP4 and Matroska files.
|
||||||
|
|
||||||
## Text encoding, Unicode support
|
## Text encoding, Unicode support
|
||||||
The library does not do any conversions for you (eg. converting Latin1 to UTF-8). However the
|
The library is aware of different text encodings and can convert between different encodings using iconv.
|
||||||
API provides a way to check which encoding is present (when reading) and which encoding(s)
|
|
||||||
can be used (when writing).
|
|
||||||
|
|
||||||
## Usage
|
## 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
|
## Bugs, stability
|
||||||
- Matroska files composed of more than one segment aren't tested yet and might not work.
|
- 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
|
- It is recommend you to create backups before editing because I can not test whether the
|
||||||
files produced by mkvmerge and ffmpeg and several other file but can't verify that it will work with all
|
library works with all kind of files.
|
||||||
files. Hence I recommend you to create backups of your files.
|
|
||||||
|
|
||||||
## Build instructions
|
## Build instructions
|
||||||
The tagparser library depends on c++utilities and is built in the same way.
|
The tagparser library depends on c++utilities and is built in the same way.
|
||||||
|
@ -53,5 +50,4 @@ It also depends on zlib.
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
- Support more formats (EXIF, PDF metadata, Theora, ...).
|
- 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.
|
- Do tests with Matroska files which have multiple segments.
|
||||||
|
|
|
@ -5,10 +5,12 @@
|
||||||
|
|
||||||
#include <c++utilities/misc/memory.h>
|
#include <c++utilities/misc/memory.h>
|
||||||
#include <c++utilities/io/catchiofailure.h>
|
#include <c++utilities/io/catchiofailure.h>
|
||||||
|
#include <c++utilities/io/copy.h>
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
using namespace IoUtilities;
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
|
|
||||||
|
@ -63,6 +65,21 @@ void StreamDataBlock::makeBuffer() const
|
||||||
stream().read(m_buffer.get(), size());
|
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
|
* \class Media::FileDataBlock
|
||||||
* \brief The FileDataBlock class is a reference to a certain data block of a file stream.
|
* \brief The FileDataBlock class is a reference to a certain data block of a file stream.
|
||||||
|
|
|
@ -27,6 +27,7 @@ public:
|
||||||
const std::unique_ptr<char[]> &buffer() const;
|
const std::unique_ptr<char[]> &buffer() const;
|
||||||
void makeBuffer() const;
|
void makeBuffer() const;
|
||||||
void discardBuffer();
|
void discardBuffer();
|
||||||
|
void copyTo(std::ostream &stream) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
StreamDataBlock();
|
StreamDataBlock();
|
||||||
|
@ -211,12 +212,10 @@ inline void AbstractAttachment::setId(const uint64 &id)
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns a reference to the data of the attachment.
|
* \brief Returns a reference to the data of the attachment.
|
||||||
*
|
* \remarks
|
||||||
* The reference might be nullptr if there is no data assigned.
|
* - The reference might be nullptr if there is no data assigned.
|
||||||
* The attachment keeps ownership over the reference.
|
* - The attachment keeps ownership over the reference.
|
||||||
*
|
* \sa setData(), setFile()
|
||||||
* \sa setData()
|
|
||||||
* \sa setFile()
|
|
||||||
*/
|
*/
|
||||||
inline const StreamDataBlock *AbstractAttachment::data() const
|
inline const StreamDataBlock *AbstractAttachment::data() const
|
||||||
{
|
{
|
||||||
|
@ -225,11 +224,8 @@ inline const StreamDataBlock *AbstractAttachment::data() const
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Sets the \a data for the attachment.
|
* \brief Sets the \a data for the attachment.
|
||||||
*
|
* \remarks The specified \a data is moved to the attachment.
|
||||||
* The specified \a data is moved to the attachment.
|
* \sa data(), setFile()
|
||||||
*
|
|
||||||
* \sa data()
|
|
||||||
* \sa setFile()
|
|
||||||
*/
|
*/
|
||||||
inline void AbstractAttachment::setData(std::unique_ptr<StreamDataBlock> &&data)
|
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.
|
* \brief Returns whether the attachment is ignored/omitted when rewriting the container.
|
||||||
*
|
*
|
||||||
* The default value is false.
|
* The default value is false.
|
||||||
*
|
|
||||||
* \sa setIgnored()
|
* \sa setIgnored()
|
||||||
*/
|
*/
|
||||||
inline bool AbstractAttachment::isIgnored() const
|
inline bool AbstractAttachment::isIgnored() const
|
||||||
|
|
|
@ -10,6 +10,16 @@ using namespace IoUtilities;
|
||||||
|
|
||||||
namespace Media {
|
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)
|
void AvcConfiguration::parse(BinaryReader &reader, uint64 maxSize)
|
||||||
{
|
{
|
||||||
if(maxSize < 7) {
|
if(maxSize < 7) {
|
||||||
|
|
|
@ -22,6 +22,9 @@ struct LIB_EXPORT AvcConfiguration
|
||||||
void parse(IoUtilities::BinaryReader &reader, uint64 maxSize);
|
void parse(IoUtilities::BinaryReader &reader, uint64 maxSize);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Constructs an empty AVC configuration.
|
||||||
|
*/
|
||||||
inline AvcConfiguration::AvcConfiguration() :
|
inline AvcConfiguration::AvcConfiguration() :
|
||||||
profileIndication(0),
|
profileIndication(0),
|
||||||
profileCompat(0),
|
profileCompat(0),
|
||||||
|
|
|
@ -273,6 +273,21 @@ void HrdParameters::parse(IoUtilities::BitReader &reader)
|
||||||
timeOffsetLength = reader.readBits<byte>(5);
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,7 +115,7 @@ inline SpsInfo::SpsInfo() :
|
||||||
size(0)
|
size(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
struct PpsInfo {
|
struct LIB_EXPORT PpsInfo {
|
||||||
PpsInfo();
|
PpsInfo();
|
||||||
ugolomb id;
|
ugolomb id;
|
||||||
ugolomb spsId;
|
ugolomb spsId;
|
||||||
|
@ -132,7 +132,7 @@ inline PpsInfo::PpsInfo() :
|
||||||
size(0)
|
size(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
struct SliceInfo {
|
struct LIB_EXPORT SliceInfo {
|
||||||
SliceInfo();
|
SliceInfo();
|
||||||
byte naluType;
|
byte naluType;
|
||||||
byte naluRefIdc;
|
byte naluRefIdc;
|
||||||
|
@ -167,7 +167,7 @@ inline SliceInfo::SliceInfo() :
|
||||||
pps(0)
|
pps(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
class AvcFrame {
|
class LIB_EXPORT AvcFrame {
|
||||||
AvcFrame();
|
AvcFrame();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <initializer_list>
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
|
|
||||||
|
@ -27,11 +28,14 @@ class FieldMapBasedTag : public Tag
|
||||||
public:
|
public:
|
||||||
FieldMapBasedTag();
|
FieldMapBasedTag();
|
||||||
|
|
||||||
virtual const TagValue &value(KnownField field) const;
|
|
||||||
virtual const TagValue &value(const typename FieldType::identifierType &id) 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 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(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(KnownField field) const;
|
||||||
virtual bool hasField(const typename FieldType::identifierType &id) const;
|
virtual bool hasField(const typename FieldType::identifierType &id) const;
|
||||||
virtual void removeAllFields();
|
virtual void removeAllFields();
|
||||||
|
@ -72,14 +76,9 @@ template <class FieldType, class Compare>
|
||||||
FieldMapBasedTag<FieldType, Compare>::FieldMapBasedTag()
|
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.
|
* \brief Returns the value of the field with the specified \a id.
|
||||||
|
* \sa Tag::value()
|
||||||
*/
|
*/
|
||||||
template <class FieldType, class Compare>
|
template <class FieldType, class Compare>
|
||||||
inline const TagValue &FieldMapBasedTag<FieldType, Compare>::value(const typename FieldType::identifierType &id) const
|
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();
|
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.
|
* \brief Returns the values of the field with the specified \a id.
|
||||||
*
|
* \sa Tag::values()
|
||||||
* There might me more then one value assigned to a \a field. Whereas value()
|
|
||||||
* returns only the first value, this method returns all values.
|
|
||||||
*/
|
*/
|
||||||
template <class FieldType, class Compare>
|
template <class FieldType, class Compare>
|
||||||
inline std::list<const TagValue *> FieldMapBasedTag<FieldType, Compare>::values(const typename FieldType::identifierType &id) const
|
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);
|
auto range = m_fields.equal_range(id);
|
||||||
std::list<const TagValue *> values;
|
std::list<const TagValue *> values;
|
||||||
for(auto i = range.first; i != range.second; ++i) {
|
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;
|
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>
|
template <class FieldType, class Compare>
|
||||||
inline bool FieldMapBasedTag<FieldType, Compare>::setValue(KnownField field, const TagValue &value)
|
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.
|
* \brief Assigns the given \a value to the field with the specified \a id.
|
||||||
|
* \sa Tag::setValue()
|
||||||
*/
|
*/
|
||||||
template <class FieldType, class Compare>
|
template <class FieldType, class Compare>
|
||||||
bool FieldMapBasedTag<FieldType, Compare>::setValue(const typename FieldType::identifierType &id, const Media::TagValue &value)
|
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);
|
auto i = m_fields.find(id);
|
||||||
if(i != m_fields.end()) { // field already exists -> set its value
|
if(i != m_fields.end()) { // field already exists -> set its value
|
||||||
i->second.setValue(value);
|
i->second.setValue(value);
|
||||||
} else if(!value.isEmpty()) {// field doesn't exist -> create new one if value is not null
|
} 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)));
|
m_fields.insert(std::make_pair(id, FieldType(id, value)));
|
||||||
} else { // otherwise return false
|
} else { // otherwise return false
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
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>
|
template <class FieldType, class Compare>
|
||||||
inline bool FieldMapBasedTag<FieldType, Compare>::hasField(KnownField field) const
|
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.
|
* \brief Returns the fields of the tag by providing direct access to the field map 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.
|
|
||||||
*/
|
*/
|
||||||
template <class FieldType, class Compare>
|
template <class FieldType, class Compare>
|
||||||
inline const std::multimap<typename FieldType::identifierType, FieldType, Compare> &FieldMapBasedTag<FieldType, Compare>::fields() const
|
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.
|
* \brief Returns the fields of the tag by providing direct access to the field map 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.
|
|
||||||
*/
|
*/
|
||||||
template <class FieldType, class Compare>
|
template <class FieldType, class Compare>
|
||||||
inline std::multimap<typename FieldType::identifierType, FieldType, Compare> &FieldMapBasedTag<FieldType, Compare>::fields()
|
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>
|
template <class FieldType, class Compare>
|
||||||
unsigned int FieldMapBasedTag<FieldType, Compare>::fieldCount() const
|
unsigned int FieldMapBasedTag<FieldType, Compare>::fieldCount() const
|
||||||
{
|
{
|
||||||
int count = 0;
|
unsigned int count = 0;
|
||||||
for(const auto &field : m_fields) {
|
for(const auto &field : m_fields) {
|
||||||
if(!field.second.value().isEmpty()) {
|
if(!field.second.value().isEmpty()) {
|
||||||
++count;
|
++count;
|
||||||
|
@ -233,7 +272,7 @@ int FieldMapBasedTag<FieldType, Compare>::insertFields(const FieldMapBasedTag<Fi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!fieldInserted) {
|
if(!fieldInserted) {
|
||||||
fields().insert(std::pair<typename FieldType::identifierType, FieldType>(fromField.id(), fromField));
|
fields().insert(std::make_pair(fromField.id(), fromField));
|
||||||
++fieldsInserted;
|
++fieldsInserted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -379,6 +379,13 @@ bool FrameComparer::operator()(const uint32 &lhs, const uint32 &rhs) const
|
||||||
return lhs < rhs;
|
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.
|
* \brief Prepares making the specified \a tag.
|
||||||
* \sa See Id3v2Tag::prepareMaking() for more information.
|
* \sa See Id3v2Tag::prepareMaking() for more information.
|
||||||
|
|
|
@ -169,15 +169,7 @@ void MatroskaAttachmentMaker::make(ostream &stream) const
|
||||||
stream.write(buff, 2);
|
stream.write(buff, 2);
|
||||||
len = EbmlElement::makeSizeDenotation(attachment().data()->size(), buff);
|
len = EbmlElement::makeSizeDenotation(attachment().data()->size(), buff);
|
||||||
stream.write(buff, len);
|
stream.write(buff, len);
|
||||||
// copy data
|
attachment().data()->copyTo(stream);
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,11 @@ using namespace ChronoUtilities;
|
||||||
|
|
||||||
namespace Media {
|
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.
|
* \brief Constructs a new MatroskaChapter for the specified \a chapterAtomElement.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -707,8 +707,10 @@ void MatroskaContainer::internalParseAttachments()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief The private SegmentData struct is used in MatroskaContainer::internalMakeFile() to store segment specific data.
|
||||||
struct SegmentData
|
struct SegmentData
|
||||||
{
|
{
|
||||||
|
/// \brief Constructs a new segment data object.
|
||||||
SegmentData() :
|
SegmentData() :
|
||||||
hasCrc32(false),
|
hasCrc32(false),
|
||||||
cuesElement(nullptr),
|
cuesElement(nullptr),
|
||||||
|
@ -723,33 +725,33 @@ struct SegmentData
|
||||||
newDataOffset(0)
|
newDataOffset(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
// whether CRC-32 checksum is present
|
/// \brief whether CRC-32 checksum is present
|
||||||
bool hasCrc32;
|
bool hasCrc32;
|
||||||
// used to make "SeekHead"-element
|
/// \brief used to make "SeekHead"-element
|
||||||
MatroskaSeekInfo seekInfo;
|
MatroskaSeekInfo seekInfo;
|
||||||
// "Cues"-element (original file)
|
/// \brief "Cues"-element (original file)
|
||||||
EbmlElement *cuesElement;
|
EbmlElement *cuesElement;
|
||||||
// used to make "Cues"-element
|
/// \brief used to make "Cues"-element
|
||||||
MatroskaCuePositionUpdater cuesUpdater;
|
MatroskaCuePositionUpdater cuesUpdater;
|
||||||
// size of the "SegmentInfo"-element
|
/// \brief size of the "SegmentInfo"-element
|
||||||
uint64 infoDataSize;
|
uint64 infoDataSize;
|
||||||
// cluster sizes
|
/// \brief cluster sizes
|
||||||
vector<uint64> clusterSizes;
|
vector<uint64> clusterSizes;
|
||||||
// first "Cluster"-element (original file)
|
/// \brief first "Cluster"-element (original file)
|
||||||
EbmlElement *firstClusterElement;
|
EbmlElement *firstClusterElement;
|
||||||
// end offset of last "Cluster"-element (original file)
|
/// \brief end offset of last "Cluster"-element (original file)
|
||||||
uint64 clusterEndOffset;
|
uint64 clusterEndOffset;
|
||||||
// start offset (in the new file)
|
/// \brief start offset (in the new file)
|
||||||
uint64 startOffset;
|
uint64 startOffset;
|
||||||
// padding (in the new file)
|
/// \brief padding (in the new file)
|
||||||
uint64 newPadding;
|
uint64 newPadding;
|
||||||
// header size (in the new file)
|
/// \brief header size (in the new file)
|
||||||
byte sizeDenotationLength;
|
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;
|
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;
|
uint64 totalSize;
|
||||||
// data offset of the segment in the new file
|
/// \brief data offset of the segment in the new file
|
||||||
uint64 newDataOffset;
|
uint64 newDataOffset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,27 @@ using namespace ConversionUtilities;
|
||||||
|
|
||||||
namespace Media {
|
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
|
* \class Media::MatroskaCuePositionUpdater
|
||||||
* \brief The MatroskaCuePositionUpdater class helps to rewrite the "Cues"-element with shifted positions.
|
* \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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -10,6 +10,11 @@ using namespace std;
|
||||||
|
|
||||||
namespace Media {
|
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.
|
* \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.
|
* \brief Parses the "EditionEntry"-element specified when constructing the object.
|
||||||
*
|
* \remarks
|
||||||
* Parses also fetched chapters and nested chapters.
|
* - Parses also fetched chapters and nested chapters.
|
||||||
*
|
* - Clears all previous parsing results.
|
||||||
* Clears all previous parsing results.
|
|
||||||
*/
|
*/
|
||||||
void MatroskaEditionEntry::parseNested()
|
void MatroskaEditionEntry::parseNested()
|
||||||
{
|
{
|
||||||
|
|
|
@ -138,16 +138,10 @@ MediaFileInfo::~MediaFileInfo()
|
||||||
* containerFormatAbbreviation(), containerFormatSubversion(), containerMimeType(),
|
* containerFormatAbbreviation(), containerFormatSubversion(), containerMimeType(),
|
||||||
* container(), mp4Container() and matroskaContainer() will return the parsed
|
* container(), mp4Container() and matroskaContainer() will return the parsed
|
||||||
* information.
|
* information.
|
||||||
*
|
|
||||||
* \throws Throws std::ios_base::failure when an IO error occurs.
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
||||||
* \throws Throws Media::Failure or a derived exception when a parsing
|
* \throws Throws Media::Failure or a derived exception when a parsing
|
||||||
* error occurs.
|
* error occurs.
|
||||||
*
|
* \sa isContainerParsed(), parseTracks(), parseTag(), parseChapters(), parseEverything()
|
||||||
* \sa isContainerParsed()
|
|
||||||
* \sa parseTracks()
|
|
||||||
* \sa parseTag()
|
|
||||||
* \sa parseChapters()
|
|
||||||
* \sa parseEverything()
|
|
||||||
*/
|
*/
|
||||||
void MediaFileInfo::parseContainerFormat()
|
void MediaFileInfo::parseContainerFormat()
|
||||||
{
|
{
|
||||||
|
@ -290,25 +284,17 @@ startParsingSignature:
|
||||||
* After calling this method the methods trackCount(), tracks(), and
|
* After calling this method the methods trackCount(), tracks(), and
|
||||||
* hasTracksOfType() will return the parsed
|
* hasTracksOfType() will return the parsed
|
||||||
* information.
|
* information.
|
||||||
*
|
|
||||||
* \throws Throws std::ios_base::failure when an IO error occurs.
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
||||||
* \throws Throws Media::Failure or a derived exception when a parsing
|
* \throws Throws Media::Failure or a derived exception when a parsing
|
||||||
* error occurs.
|
* error occurs.
|
||||||
*
|
* \remarks parseContainerFormat() must be called before.
|
||||||
* \remarks parseContainerFormat() is called before the tracks will be parsed.
|
* \sa areTracksParsed(), parseContainerFormat(), parseTags(), parseChapters(), parseEverything()
|
||||||
*
|
|
||||||
* \sa areTracksParsed()
|
|
||||||
* \sa parseContainerFormat()
|
|
||||||
* \sa parseTag()
|
|
||||||
* \sa parseChapters()
|
|
||||||
* \sa parseEverything()
|
|
||||||
*/
|
*/
|
||||||
void MediaFileInfo::parseTracks()
|
void MediaFileInfo::parseTracks()
|
||||||
{
|
{
|
||||||
if(tracksParsingStatus() != ParsingStatus::NotParsedYet) { // there's no need to read the tracks twice
|
if(tracksParsingStatus() != ParsingStatus::NotParsedYet) { // there's no need to read the tracks twice
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
parseContainerFormat(); // ensure the container format has been load yet
|
|
||||||
static const string context("parsing tracks");
|
static const string context("parsing tracks");
|
||||||
try {
|
try {
|
||||||
if(m_container) {
|
if(m_container) {
|
||||||
|
@ -359,25 +345,17 @@ void MediaFileInfo::parseTracks()
|
||||||
* mp4Tag() and allTags() will return the parsed information.
|
* mp4Tag() and allTags() will return the parsed information.
|
||||||
*
|
*
|
||||||
* Previously assigned but not applied tag information will be discarted.
|
* Previously assigned but not applied tag information will be discarted.
|
||||||
*
|
|
||||||
* \throws Throws std::ios_base::failure when an IO error occurs.
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
||||||
* \throws Throws Media::Failure or a derived exception when a parsing
|
* \throws Throws Media::Failure or a derived exception when a parsing
|
||||||
* error occurs.
|
* error occurs.
|
||||||
*
|
* \remarks parseContainerFormat() must be called before.
|
||||||
* \remarks parseContainerFormat() is called before the tags informations will be parsed.
|
* \sa isTagParsed(), parseContainerFormat(), parseTracks(), parseChapters(), parseEverything()
|
||||||
*
|
|
||||||
* \sa isTagParsed()
|
|
||||||
* \sa parseContainerFormat()
|
|
||||||
* \sa parseTracks()
|
|
||||||
* \sa parseChapters()
|
|
||||||
* \sa parseEverything()
|
|
||||||
*/
|
*/
|
||||||
void MediaFileInfo::parseTags()
|
void MediaFileInfo::parseTags()
|
||||||
{
|
{
|
||||||
if(tagsParsingStatus() != ParsingStatus::NotParsedYet) { // there's no need to read the tags twice
|
if(tagsParsingStatus() != ParsingStatus::NotParsedYet) { // there's no need to read the tags twice
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
parseContainerFormat(); // ensure the container format has been load yet
|
|
||||||
static const string context("parsing tag");
|
static const string context("parsing tag");
|
||||||
// check for id3v1 tag
|
// check for id3v1 tag
|
||||||
if(size() >= 128) {
|
if(size() >= 128) {
|
||||||
|
@ -436,14 +414,8 @@ void MediaFileInfo::parseTags()
|
||||||
* \throws Throws std::ios_base::failure when an IO error occurs.
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
||||||
* \throws Throws Media::Failure or a derived exception when a parsing
|
* \throws Throws Media::Failure or a derived exception when a parsing
|
||||||
* error occurs.
|
* error occurs.
|
||||||
*
|
* \remarks parseContainerFormat() must be called before.
|
||||||
* \remarks parseContainerFormat() is called before the tags informations will be parsed.
|
* \sa areChaptersParsed(), parseContainerFormat(), parseTracks(), parseTags(), parseEverything()
|
||||||
*
|
|
||||||
* \sa areChaptersParsed()
|
|
||||||
* \sa parseContainerFormat()
|
|
||||||
* \sa parseTracks()
|
|
||||||
* \sa parseTags()
|
|
||||||
* \sa parseEverything()
|
|
||||||
*/
|
*/
|
||||||
void MediaFileInfo::parseChapters()
|
void MediaFileInfo::parseChapters()
|
||||||
{
|
{
|
||||||
|
@ -458,15 +430,26 @@ void MediaFileInfo::parseChapters()
|
||||||
} else {
|
} else {
|
||||||
throw NotImplementedException();
|
throw NotImplementedException();
|
||||||
}
|
}
|
||||||
} catch (NotImplementedException &) {
|
} catch (const NotImplementedException &) {
|
||||||
m_chaptersParsingStatus = ParsingStatus::NotSupported;
|
m_chaptersParsingStatus = ParsingStatus::NotSupported;
|
||||||
addNotification(NotificationType::Information, "Parsing chapters is not implemented for the container format of the file.", context);
|
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;
|
m_chaptersParsingStatus = ParsingStatus::CriticalFailure;
|
||||||
addNotification(NotificationType::Critical, "Unable to parse chapters.", context);
|
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()
|
void MediaFileInfo::parseAttachments()
|
||||||
{
|
{
|
||||||
if(attachmentsParsingStatus() != ParsingStatus::NotParsedYet) { // there's no need to read the attachments twice
|
if(attachmentsParsingStatus() != ParsingStatus::NotParsedYet) { // there's no need to read the attachments twice
|
||||||
|
@ -480,10 +463,10 @@ void MediaFileInfo::parseAttachments()
|
||||||
} else {
|
} else {
|
||||||
throw NotImplementedException();
|
throw NotImplementedException();
|
||||||
}
|
}
|
||||||
} catch (NotImplementedException &) {
|
} catch (const NotImplementedException &) {
|
||||||
m_attachmentsParsingStatus = ParsingStatus::NotSupported;
|
m_attachmentsParsingStatus = ParsingStatus::NotSupported;
|
||||||
addNotification(NotificationType::Information, "Parsing attachments is not implemented for the container format of the file.", context);
|
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;
|
m_attachmentsParsingStatus = ParsingStatus::CriticalFailure;
|
||||||
addNotification(NotificationType::Critical, "Unable to parse attachments.", context);
|
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.
|
* \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.
|
* See the individual methods to for more details and exceptions which might be thrown.
|
||||||
*
|
* \sa parseContainerFormat(), parseTracks(), parseTags()
|
||||||
* \sa parseContainerFormat();
|
|
||||||
* \sa parseTracks();
|
|
||||||
* \sa parseTag();
|
|
||||||
*/
|
*/
|
||||||
void MediaFileInfo::parseEverything()
|
void MediaFileInfo::parseEverything()
|
||||||
{
|
{
|
||||||
|
|
|
@ -255,6 +255,13 @@ void Mp4Tag::make(ostream &stream)
|
||||||
prepareMaking().make(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.
|
* \brief Prepares making the specified \a tag.
|
||||||
* \sa See Mp4Tag::prepareMaking() for more information.
|
* \sa See Mp4Tag::prepareMaking() for more information.
|
||||||
|
|
|
@ -27,7 +27,14 @@ using namespace ChronoUtilities;
|
||||||
|
|
||||||
namespace Media {
|
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() :
|
Mpeg4AudioSpecificConfig::Mpeg4AudioSpecificConfig() :
|
||||||
audioObjectType(0),
|
audioObjectType(0),
|
||||||
|
@ -51,10 +58,23 @@ Mpeg4AudioSpecificConfig::Mpeg4AudioSpecificConfig() :
|
||||||
epConfig(0)
|
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() :
|
Mpeg4VideoSpecificConfig::Mpeg4VideoSpecificConfig() :
|
||||||
profile(0)
|
profile(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \class Mpeg4ElementaryStreamInfo
|
||||||
|
* \brief The Mpeg4ElementaryStreamInfo class holds MPEG-4 elementary stream info parsed using Mp4Track::parseMpeg4ElementaryStreamInfo().
|
||||||
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \class Media::Mp4Track
|
* \class Media::Mp4Track
|
||||||
* \brief Implementation of Media::AbstractTrack for the MP4 container.
|
* \brief Implementation of Media::AbstractTrack for the MP4 container.
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
|
@ -60,12 +60,10 @@ void OggContainer::reset()
|
||||||
* \sa AbstractContainer::createTag()
|
* \sa AbstractContainer::createTag()
|
||||||
* \remarks
|
* \remarks
|
||||||
* - Tracks must be parsed before because tags are stored on track level!
|
* - 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.
|
* - 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, a random track will be picked.
|
* - If tracks() array of \a target is empty, the first track/tag is picked.
|
||||||
* - Vorbis streams should always have a tag assigned yet. However, this
|
* - Vorbis streams should always have a tag assigned; this method allows creation of a tag for Vorbis streams if none is present though.
|
||||||
* methods allows creation of a tag if none has been assigned yet.
|
* - 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.
|
||||||
* - FLAC streams should always have a tag assigned yet and this method
|
|
||||||
* does NOT allow to create a tag in this case.
|
|
||||||
*/
|
*/
|
||||||
OggVorbisComment *OggContainer::createTag(const TagTarget &target)
|
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.
|
* \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
|
* This specialization is neccessary because removing the tag completely whould also
|
||||||
* remove the OGG parameter which are needed when appying the changes.
|
* 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.
|
* \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.
|
* So do NOT use this method to remove tags from Vorbis, just call Tag::removeAllFields() on \a tag.
|
||||||
* \sa AbstractContainer::removeTag()
|
|
||||||
*/
|
*/
|
||||||
bool OggContainer::removeTag(Tag *tag)
|
bool OggContainer::removeTag(Tag *tag)
|
||||||
{
|
{
|
||||||
|
|
66
tag.cpp
66
tag.cpp
|
@ -33,41 +33,71 @@ Tag::~Tag()
|
||||||
*/
|
*/
|
||||||
string Tag::toString() const
|
string Tag::toString() const
|
||||||
{
|
{
|
||||||
stringstream ss;
|
string res;
|
||||||
ss << typeName();
|
res += typeName();
|
||||||
if(supportsTarget() && !target().isEmpty()) {
|
if(supportsTarget()) {
|
||||||
ss << " targeting " << targetString();
|
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()
|
* \fn Tag::value()
|
||||||
* \brief Returns the value of the specified \a field.
|
* \brief Returns the value of the specified \a field.
|
||||||
*
|
* \remarks
|
||||||
* If no value for the specified \a field is assigned an
|
* - If the specified \a field is not present an empty TagValue will be returned.
|
||||||
* 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()
|
* \sa setValue(), hasField()
|
||||||
* \sa hasField()
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \fn Tag::setValue()
|
* \fn Tag::setValue()
|
||||||
* \brief Assigns the given \a value to the specified \a field.
|
* \brief Assigns the given \a value to the specified \a field.
|
||||||
*
|
* \remarks
|
||||||
* If an empty \a value is given, the field will be be removed.
|
* - 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
|
||||||
* \sa value()
|
* alter the first value.
|
||||||
* \sa hasField()
|
* \sa value(), hasField()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \fn Tag::hasField()
|
* \fn Tag::hasField()
|
||||||
* \brief Returns an indication whether the specified \a field is present.
|
* \brief Returns an indication whether the specified \a field is present.
|
||||||
*
|
*
|
||||||
* \sa value()
|
* \sa value(), setValue()
|
||||||
* \sa setValue()
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
2
tag.h
2
tag.h
|
@ -107,7 +107,9 @@ public:
|
||||||
virtual TagTextEncoding proposedTextEncoding() const;
|
virtual TagTextEncoding proposedTextEncoding() const;
|
||||||
virtual bool canEncodingBeUsed(TagTextEncoding encoding) const;
|
virtual bool canEncodingBeUsed(TagTextEncoding encoding) const;
|
||||||
virtual const TagValue &value(KnownField field) const = 0;
|
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 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 bool hasField(KnownField field) const = 0;
|
||||||
virtual void removeAllFields() = 0;
|
virtual void removeAllFields() = 0;
|
||||||
const std::string &version() const;
|
const std::string &version() const;
|
||||||
|
|
|
@ -329,6 +329,7 @@ pair<const char *, float> encodingParameter(TagTextEncoding tagTextEncoding)
|
||||||
/*!
|
/*!
|
||||||
* \brief Converts the value of the current TagValue object to its equivalent
|
* \brief Converts the value of the current TagValue object to its equivalent
|
||||||
* std::string representation.
|
* 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
|
* \param encoding Specifies the encoding to to be used; set to TagTextEncoding::Unspecified to use the
|
||||||
* present encoding without any character set conversion.
|
* 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.
|
* \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
|
* \brief Converts the value of the current TagValue object to its equivalent
|
||||||
* std::u16string representation.
|
* std::u16string representation.
|
||||||
* \throws Throws ConversionException on failure.
|
* \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
|
void TagValue::toWString(std::u16string &result, TagTextEncoding encoding) const
|
||||||
{
|
{
|
||||||
|
|
12
tagvalue.h
12
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
|
* \brief Converts the value of the current TagValue object to its equivalent
|
||||||
* std::wstring representation.
|
* std::wstring representation.
|
||||||
* \throws Throws ConversionException on failure.
|
* \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
|
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.
|
* \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
|
inline bool TagValue::isEmpty() const
|
||||||
{
|
{
|
||||||
|
@ -321,7 +321,7 @@ inline bool TagValue::isEmpty() const
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Clears the assigned data.
|
* \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 clearMetadata()
|
||||||
* \sa clearDataAndMetadata()
|
* \sa clearDataAndMetadata()
|
||||||
*/
|
*/
|
||||||
|
@ -333,7 +333,7 @@ inline void TagValue::clearData()
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns the size of the assigned value in bytes.
|
* \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
|
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.
|
* \remarks The usage of this meta information depends on the tag implementation.
|
||||||
* \sa setMimeType()
|
* \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.
|
* \param value Specifies the mime type.
|
||||||
* \remarks The usage of this meta information depends on the tag implementation.
|
* \remarks The usage of this meta information depends on the tag implementation.
|
||||||
* \sa mimeType()
|
* \sa mimeType()
|
||||||
|
|
Loading…
Reference in New Issue