diff --git a/taglib/mp4/mp4itemfactory.cpp b/taglib/mp4/mp4itemfactory.cpp index dbbfe5c2..1028ef50 100644 --- a/taglib/mp4/mp4itemfactory.cpp +++ b/taglib/mp4/mp4itemfactory.cpp @@ -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(payload[0]) == 0xff && + static_cast(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(payload[0]) == 'B' && + static_cast(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 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(flags), - data.mid(pos + 16, length - 16))); + value.append(MP4::CoverArt(static_cast(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; }