diff options
Diffstat (limited to 'core/metadata.cpp')
-rw-r--r-- | core/metadata.cpp | 39 |
1 files changed, 35 insertions, 4 deletions
diff --git a/core/metadata.cpp b/core/metadata.cpp index 2457c69c0..b549a5b3b 100644 --- a/core/metadata.cpp +++ b/core/metadata.cpp @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include "metadata.h" +#include "xmp_parser.h" #include "exif.h" #include "qthelper.h" #include <QString> @@ -111,6 +112,15 @@ static bool parseExif(QFile &f, struct metadata *metadata) } } +// Parse an embedded XMP block. Note that this is likely generated by +// external tools and therefore we give priority of XMP data over +// native metadata. +static void parseXMP(const char *data, size_t size, metadata *metadata) +{ + if (timestamp_t timestamp = parse_xmp(data, size)) + metadata->timestamp = timestamp; +} + static bool parseMP4(QFile &f, metadata *metadata) { f.seek(0); @@ -170,8 +180,9 @@ static bool parseMP4(QFile &f, metadata *metadata) if (!memcmp(type, "moov", 4) || !memcmp(type, "trak", 4) || - !memcmp(type, "mdia", 4)) { - // Recurse into "moov", "trak" and "mdia" atoms + !memcmp(type, "mdia", 4) || + !memcmp(type, "udta", 4)) { + // Recurse into "moov", "trak", "mdia" and "udta" atoms atom_stack.push_back(atom_size); continue; } else if (!memcmp(type, "mdhd", 4) && atom_size >= 24 && atom_size < 4096) { @@ -203,10 +214,30 @@ static bool parseMP4(QFile &f, metadata *metadata) metadata->duration.seconds = lrint((double)duration / timescale); // Timestamp is given as seconds since midnight 1904/1/1. To be convertible to the UNIX epoch // it must be larger than 2082844800. - if (timestamp >= 2082844800) { + // Note that we only set timestamp if not already set, because we give priority to XMP data. + if (!metadata->timestamp && timestamp >= 2082844800) { metadata->timestamp = timestamp - 2082844800; - // Currently, we only know how to extract timestamps, so we might just quit parsing here. + // We got our timestamp and duration. Nevertheless, we continue + // parsing, as there might still be an XMP atom. + } + } else if (!memcmp(type, "XMP_", 4) && atom_size > 32 && atom_size < 100000) { + // Parse embedded XMP data. + std::vector<char> d(atom_size); + if (f.read(&d[0], atom_size) != static_cast<int>(atom_size)) break; + + parseXMP(&d[0], atom_size, metadata); + } else if (!memcmp(type, "uuid", 4) && atom_size > 32 && atom_size < 100000) { + // UUID atoms with uid "BE7ACFCB97A942E89C71999491E3AFAC" contain XMP blocks + // according the JPEG 2000 standard. exiftools produces mp4-style videos with such + // an UUID atom. + std::vector<char> d(atom_size); + if (f.read(&d[0], atom_size) != static_cast<int>(atom_size)) + break; + + static const char xmp_uid[17] = "\xBE\x7A\xCF\xCB\x97\xA9\x42\xE8\x9C\x71\x99\x94\x91\xE3\xAF\xAC"; + if (!memcmp(&d[0], xmp_uid, 16)) { + parseXMP(&d[16], atom_size - 16, metadata); } } else { // Jump over unknown atom |