Improve documentation and consistency
This commit is contained in:
parent
8663dedf8c
commit
817a8e25e6
|
@ -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
|
||||
|
|
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.
|
||||
|
||||
## 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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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()
|
||||
* \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
66
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<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
2
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<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;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
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
|
||||
* 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()
|
||||
|
|
Loading…
Reference in New Issue