TagLib 1.6.1
============
- * Better detection of .oga files in FileRef.
+ * Better detection of the audio codec of .oga files in FileRef.
* Fixed saving of Vorbis comments to Ogg FLAC files. TagLib tried to
include the Vorbis framing bit, which is only correct for Ogg Vorbis.
* Public symbols now have explicitly set visibility to "default" on GCC.
* Added missing exports for static ID3v1 functions.
* Fixed a typo in taglib_c.pc
* Fixed a failing test on ppc64.
- * Support for binary 'covr' atom in MP4 files.
+ * Support for binary 'covr' atom in MP4 files. TagLib 1.6 treated them
+ as text atoms, which corrupted them in some cases.
TagLib 1.6
==========
--- /dev/null
+#include "../taglib/mp4/mp4coverart.h"
mp4/mp4tag.cpp
mp4/mp4item.cpp
mp4/mp4properties.cpp
+mp4/mp4coverart.cpp
)
ELSE(WITH_MP4)
SET(mp4_SRCS)
SOVERSION ${TAGLIB_LIB_MAJOR_VERSION}
INSTALL_NAME_DIR ${LIB_INSTALL_DIR}
DEFINE_SYMBOL MAKE_TAGLIB_LIB
+ LINK_INTERFACE_LIBRARIES ""
)
INSTALL(TARGETS tag
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
-INSTALL( FILES mp4file.h mp4atom.h mp4tag.h mp4item.h mp4properties.h DESTINATION ${INCLUDE_INSTALL_DIR}/taglib)
+INSTALL( FILES mp4file.h mp4atom.h mp4tag.h mp4item.h mp4properties.h mp4coverart.h DESTINATION ${INCLUDE_INSTALL_DIR}/taglib)
noinst_LTLIBRARIES = libmp4.la
-libmp4_la_SOURCES = mp4atom.cpp mp4file.cpp mp4item.cpp mp4properties.cpp mp4tag.cpp
+libmp4_la_SOURCES = mp4atom.cpp mp4file.cpp mp4item.cpp mp4properties.cpp mp4tag.cpp mp4coverart.cpp
-taglib_include_HEADERS = mp4atom.h mp4file.h mp4item.h mp4properties.h mp4tag.h
+taglib_include_HEADERS = mp4atom.h mp4file.h mp4item.h mp4properties.h mp4tag.h mp4coverart.h
taglib_includedir = $(includedir)/taglib
--- /dev/null
+/**************************************************************************
+ copyright : (C) 2009 by Lukáš Lalinský
+ email : lalinsky@gmail.com
+ **************************************************************************/
+
+/***************************************************************************
+ * This library is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU Lesser General Public License version *
+ * 2.1 as published by the Free Software Foundation. *
+ * *
+ * This library is distributed in the hope that it will be useful, but *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with this library; if not, write to the Free Software *
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
+ * USA *
+ * *
+ * Alternatively, this file is available under the Mozilla Public *
+ * License Version 1.1. You may obtain a copy of the License at *
+ * http://www.mozilla.org/MPL/ *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WITH_MP4
+
+#include <taglib.h>
+#include <tdebug.h>
+#include "mp4coverart.h"
+
+using namespace TagLib;
+
+class MP4::CoverArt::CoverArtPrivate : public RefCounter
+{
+public:
+ CoverArtPrivate() : RefCounter(), format(MP4::CoverArt::JPEG) {}
+
+ Format format;
+ ByteVector data;
+};
+
+MP4::CoverArt::CoverArt(Format format, const ByteVector &data)
+{
+ d = new CoverArtPrivate;
+ d->format = format;
+ d->data = data;
+}
+
+MP4::CoverArt::CoverArt(const CoverArt &item) : d(item.d)
+{
+ d->ref();
+}
+
+MP4::CoverArt &
+MP4::CoverArt::operator=(const CoverArt &item)
+{
+ if(d->deref()) {
+ delete d;
+ }
+ d = item.d;
+ d->ref();
+ return *this;
+}
+
+MP4::CoverArt::~CoverArt()
+{
+ if(d->deref()) {
+ delete d;
+ }
+}
+
+MP4::CoverArt::Format
+MP4::CoverArt::format() const
+{
+ return d->format;
+}
+
+ByteVector
+MP4::CoverArt::data() const
+{
+ return d->data;
+}
+
+#endif
--- /dev/null
+/**************************************************************************
+ copyright : (C) 2009 by Lukáš Lalinský
+ email : lalinsky@gmail.com
+ **************************************************************************/
+
+/***************************************************************************
+ * This library is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU Lesser General Public License version *
+ * 2.1 as published by the Free Software Foundation. *
+ * *
+ * This library is distributed in the hope that it will be useful, but *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with this library; if not, write to the Free Software *
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
+ * USA *
+ * *
+ * Alternatively, this file is available under the Mozilla Public *
+ * License Version 1.1. You may obtain a copy of the License at *
+ * http://www.mozilla.org/MPL/ *
+ ***************************************************************************/
+
+#ifndef TAGLIB_MP4COVERART_H
+#define TAGLIB_MP4COVERART_H
+
+#include "tlist.h"
+#include "tbytevector.h"
+#include "taglib_export.h"
+
+namespace TagLib {
+
+ namespace MP4 {
+
+ class TAGLIB_EXPORT CoverArt
+ {
+ public:
+ /*!
+ * This describes the image type.
+ */
+ enum Format {
+ JPEG = 0x0D,
+ PNG = 0x0E
+ };
+
+ CoverArt(Format format, const ByteVector &data);
+ ~CoverArt();
+
+ CoverArt(const CoverArt &item);
+ CoverArt &operator=(const CoverArt &item);
+
+ //! Format of the image
+ Format format() const;
+
+ //! The image data
+ ByteVector data() const;
+
+ private:
+ class CoverArtPrivate;
+ CoverArtPrivate *d;
+ };
+
+ typedef List<CoverArt> CoverArtList;
+
+ }
+
+}
+
+#endif
IntPair m_intPair;
};
StringList m_stringList;
+ MP4::CoverArtList m_coverArtList;
};
MP4::Item::Item()
d->m_stringList = value;
}
+MP4::Item::Item(const MP4::CoverArtList &value)
+{
+ d = new ItemPrivate;
+ d->m_coverArtList = value;
+}
+
bool
MP4::Item::toBool() const
{
return d->m_stringList;
}
+MP4::CoverArtList
+MP4::Item::toCoverArtList() const
+{
+ return d->m_coverArtList;
+}
+
bool
MP4::Item::isValid() const
{
#define TAGLIB_MP4ITEM_H
#include "tstringlist.h"
+#include "mp4coverart.h"
#include "taglib_export.h"
namespace TagLib {
Item(bool value);
Item(int first, int second);
Item(const StringList &value);
+ Item(const CoverArtList &value);
int toInt() const;
bool toBool() const;
IntPair toIntPair() const;
StringList toStringList() const;
+ CoverArtList toCoverArtList() const;
bool isValid() const;
else if(atom->name == "gnre") {
parseGnre(atom, file);
}
+ else if(atom->name == "covr") {
+ parseCovr(atom, file);
+ }
else {
parseText(atom, file);
}
}
}
+void
+MP4::Tag::parseCovr(MP4::Atom *atom, TagLib::File *file)
+{
+ MP4::CoverArtList value;
+ ByteVector data = file->readBlock(atom->length - 8);
+ unsigned int pos = 0;
+ while(pos < data.size()) {
+ int length = data.mid(pos, 4).toUInt();
+ ByteVector name = data.mid(pos + 4, 4);
+ int flags = data.mid(pos + 8, 4).toUInt();
+ if(name != "data") {
+ debug("MP4: Unexpected atom \"" + name + "\", expecting \"data\"");
+ return;
+ }
+ if(flags == MP4::CoverArt::PNG || flags == MP4::CoverArt::JPEG) {
+ value.append(MP4::CoverArt(MP4::CoverArt::Format(flags),
+ data.mid(pos + 16, length - 16)));
+ }
+ pos += length;
+ }
+ if(value.size() > 0)
+ d->items.insert(atom->name, value);
+}
+
ByteVector
MP4::Tag::padIlst(const ByteVector &data, int length)
{
return renderData(name, flags, data);
}
+ByteVector
+MP4::Tag::renderCovr(const ByteVector &name, MP4::Item &item)
+{
+ ByteVector data;
+ MP4::CoverArtList value = item.toCoverArtList();
+ for(unsigned int i = 0; i < value.size(); i++) {
+ data.append(renderAtom("data", ByteVector::fromUInt(value[i].format()) +
+ ByteVector(4, '\0') + value[i].data()));
+ }
+ return renderAtom(name, data);
+}
+
ByteVector
MP4::Tag::renderFreeForm(const String &name, MP4::Item &item)
{
else if(name == "tmpo") {
data.append(renderInt(name.data(String::Latin1), i->second));
}
+ else if(name == "covr") {
+ data.append(renderCovr(name.data(String::Latin1), i->second));
+ }
else if(name.size() == 4){
data.append(renderText(name.data(String::Latin1), i->second));
}
void parseGnre(Atom *atom, TagLib::File *file);
void parseIntPair(Atom *atom, TagLib::File *file);
void parseBool(Atom *atom, TagLib::File *file);
+ void parseCovr(Atom *atom, TagLib::File *file);
TagLib::ByteVector padIlst(const ByteVector &data, int length = -1);
TagLib::ByteVector renderAtom(const ByteVector &name, const TagLib::ByteVector &data);
TagLib::ByteVector renderInt(const ByteVector &name, Item &item);
TagLib::ByteVector renderIntPair(const ByteVector &name, Item &item);
TagLib::ByteVector renderIntPairNoTrailing(const ByteVector &name, Item &item);
+ TagLib::ByteVector renderCovr(const ByteVector &name, Item &item);
void updateParents(AtomList &path, long delta, int ignore = 0);
void updateOffsets(long delta, long offset);
test_oggflac.cpp
)
IF(WITH_MP4)
- SET(test_runner_SRCS ${test_runner_SRCS} test_mp4.cpp)
+ SET(test_runner_SRCS ${test_runner_SRCS}
+ test_mp4.cpp
+ test_mp4item.cpp
+ test_mp4coverart.cpp
+ )
ENDIF(WITH_MP4)
IF(WITH_ASF)
CPPUNIT_TEST(testUpdateStco);
CPPUNIT_TEST(testSaveExisingWhenIlstIsLast);
CPPUNIT_TEST(test64BitAtom);
+ CPPUNIT_TEST(testCovrRead);
+ CPPUNIT_TEST(testCovrWrite);
CPPUNIT_TEST_SUITE_END();
public:
deleteFile(filename);
}
+ void testCovrRead()
+ {
+ MP4::File *f = new MP4::File("data/has-tags.m4a");
+ CPPUNIT_ASSERT(f->tag()->itemListMap().contains("covr"));
+ MP4::CoverArtList l = f->tag()->itemListMap()["covr"].toCoverArtList();
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), l.size());
+ CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[0].format());
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(79), l[0].data().size());
+ CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::JPEG, l[1].format());
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(287), l[1].data().size());
+ }
+
+ void testCovrWrite()
+ {
+ string filename = copyFile("has-tags", ".m4a");
+
+ MP4::File *f = new MP4::File(filename.c_str());
+ CPPUNIT_ASSERT(f->tag()->itemListMap().contains("covr"));
+ MP4::CoverArtList l = f->tag()->itemListMap()["covr"].toCoverArtList();
+ l.append(MP4::CoverArt(MP4::CoverArt::PNG, "foo"));
+ f->tag()->itemListMap()["covr"] = l;
+ f->save();
+ delete f;
+
+ f = new MP4::File(filename.c_str());
+ CPPUNIT_ASSERT(f->tag()->itemListMap().contains("covr"));
+ l = f->tag()->itemListMap()["covr"].toCoverArtList();
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(3), l.size());
+ CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[0].format());
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(79), l[0].data().size());
+ CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::JPEG, l[1].format());
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(287), l[1].data().size());
+ CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[2].format());
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(3), l[2].data().size());
+ delete f;
+
+ deleteFile(filename);
+ }
+
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestMP4);
--- /dev/null
+#include <cppunit/extensions/HelperMacros.h>
+#include <string>
+#include <stdio.h>
+#include <tag.h>
+#include <mp4coverart.h>
+#include "utils.h"
+
+using namespace std;
+using namespace TagLib;
+
+class TestMP4CoverArt : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(TestMP4CoverArt);
+ CPPUNIT_TEST(testSimple);
+ CPPUNIT_TEST(testList);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+
+ void testSimple()
+ {
+ MP4::CoverArt c(MP4::CoverArt::PNG, "foo");
+ CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, c.format());
+ CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), c.data());
+
+ MP4::CoverArt c2(c);
+ CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, c2.format());
+ CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), c2.data());
+
+ MP4::CoverArt c3 = c;
+ CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, c3.format());
+ CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), c3.data());
+ }
+
+ void testList()
+ {
+ MP4::CoverArtList l;
+ l.append(MP4::CoverArt(MP4::CoverArt::PNG, "foo"));
+ l.append(MP4::CoverArt(MP4::CoverArt::JPEG, "bar"));
+
+ CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[0].format());
+ CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), l[0].data());
+ CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::JPEG, l[1].format());
+ CPPUNIT_ASSERT_EQUAL(ByteVector("bar"), l[1].data());
+ }
+
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TestMP4CoverArt);
--- /dev/null
+#include <cppunit/extensions/HelperMacros.h>
+#include <string>
+#include <stdio.h>
+#include <tag.h>
+#include <mp4coverart.h>
+#include <mp4item.h>
+#include "utils.h"
+
+using namespace std;
+using namespace TagLib;
+
+class TestMP4Item : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(TestMP4Item);
+ CPPUNIT_TEST(testCoverArtList);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+
+ void testCoverArtList()
+ {
+ MP4::CoverArtList l;
+ l.append(MP4::CoverArt(MP4::CoverArt::PNG, "foo"));
+ l.append(MP4::CoverArt(MP4::CoverArt::JPEG, "bar"));
+
+ MP4::Item i(l);
+ MP4::CoverArtList l2 = i.toCoverArtList();
+
+ CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[0].format());
+ CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), l[0].data());
+ CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::JPEG, l[1].format());
+ CPPUNIT_ASSERT_EQUAL(ByteVector("bar"), l[1].data());
+ }
+
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TestMP4Item);