MP4: Allow extracting covr with wrong flags (#1383)

If the covr has invalid flags, detect the image format from the magic bytes
and return the image anyways even if the type is unknown.
This commit is contained in:
MSOB7Y
2026-08-01 07:32:43 +02:00
committed by GitHub
parent e8f1e058d6
commit a100d0b2ec
+31 -3
View File
@@ -30,6 +30,7 @@
#include "tbytevector.h"
#include "tdebug.h"
#include "tutils.h"
#include "id3v1genres.h"
@@ -40,6 +41,25 @@ namespace {
constexpr char freeFormPrefix[] = "----:com.apple.iTunes:";
MP4::CoverArt::Format detectImageFormat(const ByteVector &payload)
{
const unsigned int size = payload.size();
if(size >= 2 &&
static_cast<unsigned char>(payload[0]) == 0xff &&
static_cast<unsigned char>(payload[1]) == 0xd8)
return MP4::CoverArt::JPEG;
if(size >= 8 && payload.startsWith("\x89PNG\x0d\x0a\x1a\x0a"))
return MP4::CoverArt::PNG;
if(size >= 6 && payload.startsWith("GIF8"))
return MP4::CoverArt::GIF;
if(size >= 14 &&
static_cast<unsigned char>(payload[0]) == 'B' &&
static_cast<unsigned char>(payload[1]) == 'M' &&
payload.toUInt(6, false) == 0)
return MP4::CoverArt::BMP;
return MP4::CoverArt::Unknown;
}
} // namespace
class ItemFactory::ItemFactoryPrivate
@@ -625,13 +645,21 @@ std::pair<String, Item> ItemFactory::parseCovr(
debug("MP4: Unexpected atom \"" + name + "\", expecting \"data\"");
break;
}
const ByteVector payload = data.mid(pos + 16, length - 16);
if(flags == TypeJPEG || flags == TypePNG || flags == TypeBMP ||
flags == TypeGIF || flags == TypeImplicit) {
value.append(MP4::CoverArt(static_cast<MP4::CoverArt::Format>(flags),
data.mid(pos + 16, length - 16)));
value.append(MP4::CoverArt(static_cast<MP4::CoverArt::Format>(flags), payload));
}
else {
debug("MP4: Unknown covr format " + String::number(flags));
// The flags field holds an unexpected type written by several buggy encoders/taggers
// (e.g. files where flags == TypeUTF8 == 1 but the payload is a JPEG image).
// Because 'covr' is semantically an image-only atom, try to recover the
// real format by sniffing the payload's magic bytes rather than silently
// discarding the artwork.
const auto format = detectImageFormat(payload);
debug(Utils::formatString(
"MP4: Replacing unexpected covr flags %d by detected format %d", flags, format));
value.append(MP4::CoverArt(format, payload));
}
pos += length;
}