6 #include "../exceptions.h"
8 #include <c++utilities/conversion/stringconversion.h>
9 #include <c++utilities/io/binarywriter.h>
28 case KnownField::EncoderSettings:
52 case TagTextEncoding::Utf16BigEndian:
70 case KnownField::EncoderSettings:
85 std::vector<const TagValue *> Mp4Tag::values(
KnownField field)
const
90 for (
auto i = range.first; i != range.second; ++i) {
91 const auto &extendedField = i->second;
92 if (extendedId.matches(extendedField)) {
93 values.emplace_back(&extendedField.value());
94 for (
const auto &additionalData : extendedField.additionalData()) {
95 values.emplace_back(&additionalData.value);
108 const TagValue &Mp4Tag::value(std::string_view mean, std::string_view name)
const
111 for (
auto i = range.first; i != range.second; ++i) {
112 if (i->second.mean() == mean && i->second.name() == name) {
113 return i->second.value();
116 return TagValue::empty();
121 using namespace Mp4TagAtomIds;
129 case KnownField::RecordDate:
169 KnownField Mp4Tag::internallyGetKnownField(
const IdentifierType &
id)
const
171 using namespace Mp4TagAtomIds;
180 return KnownField::RecordDate;
215 return KnownField::Invalid;
223 void Mp4Tag::internallyGetValuesFromField(
const Mp4Tag::FieldType &field, std::vector<const TagValue *> &values)
const
225 if (!field.value().isEmpty()) {
226 values.emplace_back(&field.value());
228 for (
const auto &value : field.additionalData()) {
229 if (!value.value.isEmpty()) {
230 values.emplace_back(&value.value);
239 switch (value.
type()) {
240 case TagDataType::StandardGenreIndex:
247 case KnownField::EncoderSettings:
259 bool Mp4Tag::setValues(
KnownField field,
const std::vector<TagValue> &values)
262 auto valuesIterator = values.cbegin();
264 for (; valuesIterator != values.cend() && range.first != range.second;) {
265 if (!valuesIterator->isEmpty()) {
266 auto &extendedField = range.first->second;
267 if (extendedId.matches(extendedField) && (!extendedId.updateOnly || !extendedField.value().isEmpty())) {
268 extendedField.clearValue();
269 extendedField.setValue(*valuesIterator);
280 for (; valuesIterator != values.cend(); ++valuesIterator) {
282 std::forward_as_tuple(extendedId.mean, extendedId.name, *valuesIterator));
284 for (; range.first != range.second; ++range.first) {
285 range.first->second.clearValue();
298 bool Mp4Tag::setValue(std::string_view mean, std::string_view name,
const TagValue &value)
301 for (
auto i = range.first; i != range.second; ++i) {
302 if (i->second.mean() == mean && i->second.name() == name) {
303 i->second.setValue(value);
330 static const string context(
"parsing MP4 tag");
331 istream &stream = metaAtom.
container().stream();
332 BinaryReader &reader = metaAtom.
container().reader();
333 if (metaAtom.
totalSize() > numeric_limits<std::uint32_t>::max()) {
334 diag.emplace_back(DiagLevel::Critical,
"Can't handle such big \"meta\" atoms.", context);
337 m_size =
static_cast<std::uint32_t
>(metaAtom.
totalSize());
342 diag.emplace_back(DiagLevel::Critical,
"Unable to parse child atoms of meta atom (stores hdlr and ilst atoms).", context);
346 int versionByte = reader.readByte();
347 if (versionByte != 0) {
348 diag.emplace_back(DiagLevel::Warning,
"Version is unknown.", context);
350 if (reader.readUInt24BE()) {
351 diag.emplace_back(DiagLevel::Warning,
"Flags (hdlr atom) aren't set to 0.", context);
353 if (reader.readInt32BE()) {
354 diag.emplace_back(DiagLevel::Warning,
"Predefined 32-bit integer (hdlr atom) ins't set to 0.", context);
356 std::uint64_t handlerType = reader.readUInt64BE();
357 if ( (handlerType != 0x6d6469726170706c)) {
358 diag.emplace_back(DiagLevel::Warning,
"Handler type (value in hdlr atom) is unknown. Trying to parse meta information anyhow.", context);
360 m_version = numberToString(versionByte);
367 diag.emplace_back(DiagLevel::Critical,
"Unable to parse child atoms of meta atom (stores hdlr and ilst atoms).", context);
370 diag.emplace_back(DiagLevel::Warning,
"No ilst atom found (stores attached meta information).", context);
377 tagField.
reparse(*child, diag);
378 fields().emplace(child->id(), move(tagField));
407 prepareMaking(diag).make(stream, diag);
431 m_omitPreDefinedGenre(m_tag.fields().count(m_tag.hasField(Mp4TagAtomIds::
Genre)))
433 m_maker.reserve(m_tag.fields().size());
434 for (
auto &field : m_tag.fields()) {
437 m_ilstSize += m_maker.emplace_back(field.second.prepareMaking(diag)).requiredSize();
438 }
catch (
const Failure &) {
442 if (m_ilstSize != 8) {
443 m_metaSize += m_ilstSize;
445 if (m_metaSize >= numeric_limits<std::uint32_t>::max()) {
446 diag.emplace_back(
DiagLevel::Critical,
"Making such big tags is not implemented.",
"making MP4 tag");
447 throw NotImplementedException();
461 BinaryWriter writer(&stream);
462 writer.writeUInt32BE(
static_cast<std::uint32_t
>(m_metaSize));
465 static const std::uint8_t hdlrData[37] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x68, 0x64, 0x6C, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00,
466 0x00, 0x00, 0x00, 0x6D, 0x64, 0x69, 0x72, 0x61, 0x70, 0x70, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
467 stream.write(
reinterpret_cast<const char *
>(hdlrData),
sizeof(hdlrData));
468 if (m_ilstSize != 8) {
470 writer.writeUInt32BE(
static_cast<std::uint32_t
>(m_ilstSize));
473 for (
auto &maker : m_maker) {
The Diagnostics class is a container for DiagMessage.
The class inherits from std::exception and serves as base class for exceptions thrown by the elements...
The FieldMapBasedTag provides a generic implementation of Tag which stores the tag fields using std::...
typename FieldMapBasedTagTraits< Mp4Tag >::FieldType::IdentifierType IdentifierType
typename FieldMapBasedTagTraits< Mp4Tag >::FieldType FieldType
std::uint64_t startOffset() const
Returns the start offset in the related stream.
std::uint32_t headerSize() const
Returns the header size of the element in byte.
ImplementationType * childById(const IdentifierType &id, Diagnostics &diag)
Returns the first child with the specified id.
ImplementationType * nextSibling()
Returns the next sibling of the element.
ImplementationType * firstChild()
Returns the first child of the element.
std::uint64_t totalSize() const
Returns the total size of the element.
ContainerType & container()
Returns the related container.
The Mp4Atom class helps to parse MP4 files.
The Mp4TagField class is used by Mp4Tag to store the fields.
void reparse(Mp4Atom &ilstChild, Diagnostics &diag)
Parses field information from the specified Mp4Atom.
The Mp4TagMaker class helps writing MP4 tags.
void make(std::ostream &stream, Diagnostics &diag)
Saves the tag (specified when constructing the object) to the specified stream.
Implementation of TagParser::Tag for the MP4 container.
The exception that is thrown when the data to be parsed holds no parsable information (e....
This exception is thrown when the an operation is invoked that has not been implemented yet.
The TagValue class wraps values of different types.
TagDataType type() const
Returns the type of the assigned value.
bool isEmpty() const
Returns whether no or an empty value is assigned.
Contains all classes and functions of the TagInfo library.
KnownField
Specifies the field.
TagTextEncoding
Specifies the text encoding.
The Mp4ExtendedFieldId specifies parameter for an extended field denoted via Mp4TagAtomIds::Extended.