mpeg/id3v2/id3v2tag.h
mpeg/id3v2/frames/attachedpictureframe.h
mpeg/id3v2/frames/commentsframe.h
+ mpeg/id3v2/frames/eventtimingcodesframe.h
mpeg/id3v2/frames/generalencapsulatedobjectframe.h
mpeg/id3v2/frames/ownershipframe.h
mpeg/id3v2/frames/popularimeterframe.h
set(frames_SRCS
mpeg/id3v2/frames/attachedpictureframe.cpp
mpeg/id3v2/frames/commentsframe.cpp
+ mpeg/id3v2/frames/eventtimingcodesframe.cpp
mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp
mpeg/id3v2/frames/ownershipframe.cpp
mpeg/id3v2/frames/popularimeterframe.cpp
--- /dev/null
+/***************************************************************************
+ copyright : (C) 2014 by Urs Fleisch
+ email : ufleisch@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA *
+ * 02110-1301 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/ *
+ ***************************************************************************/
+
+#include "eventtimingcodesframe.h"
+#include <tbytevectorlist.h>
+#include <id3v2tag.h>
+#include <tdebug.h>
+#include <tpropertymap.h>
+
+using namespace TagLib;
+using namespace ID3v2;
+
+class EventTimingCodesFrame::EventTimingCodesFramePrivate
+{
+public:
+ EventTimingCodesFramePrivate() :
+ timestampFormat(EventTimingCodesFrame::AbsoluteMilliseconds) {}
+ EventTimingCodesFrame::TimestampFormat timestampFormat;
+ EventTimingCodesFrame::SynchedEventList synchedEvents;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// public members
+////////////////////////////////////////////////////////////////////////////////
+
+EventTimingCodesFrame::EventTimingCodesFrame() :
+ Frame("ETCO")
+{
+ d = new EventTimingCodesFramePrivate;
+}
+
+EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data) :
+ Frame(data)
+{
+ d = new EventTimingCodesFramePrivate;
+ setData(data);
+}
+
+EventTimingCodesFrame::~EventTimingCodesFrame()
+{
+ delete d;
+}
+
+String EventTimingCodesFrame::toString() const
+{
+ return String();
+}
+
+EventTimingCodesFrame::TimestampFormat
+EventTimingCodesFrame::timestampFormat() const
+{
+ return d->timestampFormat;
+}
+
+EventTimingCodesFrame::SynchedEventList
+EventTimingCodesFrame::synchedEvents() const
+{
+ return d->synchedEvents;
+}
+
+void EventTimingCodesFrame::setTimestampFormat(
+ EventTimingCodesFrame::TimestampFormat f)
+{
+ d->timestampFormat = f;
+}
+
+void EventTimingCodesFrame::setSynchedEvents(
+ const EventTimingCodesFrame::SynchedEventList &e)
+{
+ d->synchedEvents = e;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// protected members
+////////////////////////////////////////////////////////////////////////////////
+
+void EventTimingCodesFrame::parseFields(const ByteVector &data)
+{
+ const int end = data.size();
+ if(end < 1) {
+ debug("An event timing codes frame must contain at least 1 byte.");
+ return;
+ }
+
+ d->timestampFormat = TimestampFormat(data[0]);
+
+ int pos = 1;
+ d->synchedEvents.clear();
+ while(pos + 4 < end) {
+ EventType type = EventType(uchar(data[pos++]));
+ uint time = data.toUInt(pos, true);
+ pos += 4;
+ d->synchedEvents.append(SynchedEvent(time, type));
+ }
+}
+
+ByteVector EventTimingCodesFrame::renderFields() const
+{
+ ByteVector v;
+
+ v.append(char(d->timestampFormat));
+ for(SynchedEventList::ConstIterator it = d->synchedEvents.begin();
+ it != d->synchedEvents.end();
+ ++it) {
+ const SynchedEvent &entry = *it;
+ v.append(char(entry.type));
+ v.append(ByteVector::fromUInt(entry.time));
+ }
+
+ return v;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// private members
+////////////////////////////////////////////////////////////////////////////////
+
+EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data, Header *h)
+ : Frame(h)
+{
+ d = new EventTimingCodesFramePrivate();
+ parseFields(fieldData(data));
+}
--- /dev/null
+/***************************************************************************
+ copyright : (C) 2014 by Urs Fleisch
+ email : ufleisch@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA *
+ * 02110-1301 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_EVENTTIMINGCODESFRAME_H
+#define TAGLIB_EVENTTIMINGCODESFRAME_H
+
+#include "id3v2frame.h"
+#include "tlist.h"
+
+namespace TagLib {
+
+ namespace ID3v2 {
+
+ //! ID3v2 event timing codes frame
+ /*!
+ * An implementation of ID3v2 event timing codes.
+ */
+ class TAGLIB_EXPORT EventTimingCodesFrame : public Frame
+ {
+ friend class FrameFactory;
+
+ public:
+
+ /*!
+ * Specifies the timestamp format used.
+ */
+ enum TimestampFormat {
+ //! The timestamp is of unknown format.
+ Unknown = 0x00,
+ //! The timestamp represents the number of MPEG frames since
+ //! the beginning of the audio stream.
+ AbsoluteMpegFrames = 0x01,
+ //! The timestamp represents the number of milliseconds since
+ //! the beginning of the audio stream.
+ AbsoluteMilliseconds = 0x02
+ };
+
+ /*!
+ * Event types defined in id3v2.4.0-frames.txt 4.5. Event timing codes.
+ */
+ enum EventType {
+ Padding = 0x00,
+ EndOfInitialSilence = 0x01,
+ IntroStart = 0x02,
+ MainPartStart = 0x03,
+ OutroStart = 0x04,
+ OutroEnd = 0x05,
+ VerseStart = 0x06,
+ RefrainStart = 0x07,
+ InterludeStart = 0x08,
+ ThemeStart = 0x09,
+ VariationStart = 0x0a,
+ KeyChange = 0x0b,
+ TimeChange = 0x0c,
+ MomentaryUnwantedNoise = 0x0d,
+ SustainedNoise = 0x0e,
+ SustainedNoiseEnd = 0x0f,
+ IntroEnd = 0x10,
+ MainPartEnd = 0x11,
+ VerseEnd = 0x12,
+ RefrainEnd = 0x13,
+ ThemeEnd = 0x14,
+ Profanity = 0x15,
+ ProfanityEnd = 0x16,
+ NotPredefinedSynch0 = 0xe0,
+ NotPredefinedSynch1 = 0xe1,
+ NotPredefinedSynch2 = 0xe2,
+ NotPredefinedSynch3 = 0xe3,
+ NotPredefinedSynch4 = 0xe4,
+ NotPredefinedSynch5 = 0xe5,
+ NotPredefinedSynch6 = 0xe6,
+ NotPredefinedSynch7 = 0xe7,
+ NotPredefinedSynch8 = 0xe8,
+ NotPredefinedSynch9 = 0xe9,
+ NotPredefinedSynchA = 0xea,
+ NotPredefinedSynchB = 0xeb,
+ NotPredefinedSynchC = 0xec,
+ NotPredefinedSynchD = 0xed,
+ NotPredefinedSynchE = 0xee,
+ NotPredefinedSynchF = 0xef,
+ AudioEnd = 0xfd,
+ AudioFileEnds = 0xfe
+ };
+
+ /*!
+ * Single entry of time stamp and event.
+ */
+ struct SynchedEvent {
+ SynchedEvent(uint ms, EventType t) : time(ms), type(t) {}
+ uint time;
+ EventType type;
+ };
+
+ /*!
+ * List of synchronized events.
+ */
+ typedef TagLib::List<SynchedEvent> SynchedEventList;
+
+ /*!
+ * Construct an empty event timing codes frame.
+ */
+ explicit EventTimingCodesFrame();
+
+ /*!
+ * Construct a event timing codes frame based on the data in \a data.
+ */
+ explicit EventTimingCodesFrame(const ByteVector &data);
+
+ /*!
+ * Destroys this EventTimingCodesFrame instance.
+ */
+ virtual ~EventTimingCodesFrame();
+
+ /*!
+ * Returns a null string.
+ */
+ virtual String toString() const;
+
+ /*!
+ * Returns the timestamp format.
+ */
+ TimestampFormat timestampFormat() const;
+
+ /*!
+ * Returns the events with the time stamps.
+ */
+ SynchedEventList synchedEvents() const;
+
+ /*!
+ * Set the timestamp format.
+ *
+ * \see timestampFormat()
+ */
+ void setTimestampFormat(TimestampFormat f);
+
+ /*!
+ * Sets the text with the time stamps.
+ *
+ * \see text()
+ */
+ void setSynchedEvents(const SynchedEventList &e);
+
+ protected:
+ // Reimplementations.
+
+ virtual void parseFields(const ByteVector &data);
+ virtual ByteVector renderFields() const;
+
+ private:
+ /*!
+ * The constructor used by the FrameFactory.
+ */
+ EventTimingCodesFrame(const ByteVector &data, Header *h);
+ EventTimingCodesFrame(const EventTimingCodesFrame &);
+ EventTimingCodesFrame &operator=(const EventTimingCodesFrame &);
+
+ class EventTimingCodesFramePrivate;
+ EventTimingCodesFramePrivate *d;
+ };
+
+ }
+}
+#endif
#include "frames/privateframe.h"
#include "frames/ownershipframe.h"
#include "frames/synchronizedlyricsframe.h"
+#include "frames/eventtimingcodesframe.h"
using namespace TagLib;
using namespace ID3v2;
return f;
}
+ // Event timing codes (frames 4.5)
+
+ if(frameID == "ETCO")
+ return new EventTimingCodesFrame(data, header);
+
// Popularimeter (frames 4.17)
if(frameID == "POPM")
#include <attachedpictureframe.h>
#include <unsynchronizedlyricsframe.h>
#include <synchronizedlyricsframe.h>
+#include <eventtimingcodesframe.h>
#include <generalencapsulatedobjectframe.h>
#include <relativevolumeframe.h>
#include <popularimeterframe.h>
CPPUNIT_TEST(testRenderOwnershipFrame);
CPPUNIT_TEST(testParseSynchronizedLyricsFrame);
CPPUNIT_TEST(testRenderSynchronizedLyricsFrame);
+ CPPUNIT_TEST(testParseEventTimingCodesFrame);
+ CPPUNIT_TEST(testRenderEventTimingCodesFrame);
CPPUNIT_TEST(testSaveUTF16Comment);
CPPUNIT_TEST(testUpdateGenre23_1);
CPPUNIT_TEST(testUpdateGenre23_2);
f.render());
}
+ void testParseEventTimingCodesFrame()
+ {
+ ID3v2::EventTimingCodesFrame f(
+ ByteVector("ETCO" // Frame ID
+ "\x00\x00\x00\x0b" // Frame size
+ "\x00\x00" // Frame flags
+ "\x02" // Time stamp format
+ "\x02" // 1st event
+ "\x00\x00\xf3\x5c" // 1st time stamp
+ "\xfe" // 2nd event
+ "\x00\x36\xee\x80", 21)); // 2nd time stamp
+ CPPUNIT_ASSERT_EQUAL(ID3v2::EventTimingCodesFrame::AbsoluteMilliseconds,
+ f.timestampFormat());
+ ID3v2::EventTimingCodesFrame::SynchedEventList sel = f.synchedEvents();
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), sel.size());
+ CPPUNIT_ASSERT_EQUAL(ID3v2::EventTimingCodesFrame::IntroStart, sel[0].type);
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(62300), sel[0].time);
+ CPPUNIT_ASSERT_EQUAL(ID3v2::EventTimingCodesFrame::AudioFileEnds, sel[1].type);
+ CPPUNIT_ASSERT_EQUAL(TagLib::uint(3600000), sel[1].time);
+ }
+
+ void testRenderEventTimingCodesFrame()
+ {
+ ID3v2::EventTimingCodesFrame f;
+ f.setTimestampFormat(ID3v2::EventTimingCodesFrame::AbsoluteMilliseconds);
+ ID3v2::EventTimingCodesFrame::SynchedEventList sel;
+ sel.append(ID3v2::EventTimingCodesFrame::SynchedEvent(62300, ID3v2::EventTimingCodesFrame::IntroStart));
+ sel.append(ID3v2::EventTimingCodesFrame::SynchedEvent(3600000, ID3v2::EventTimingCodesFrame::AudioFileEnds));
+ f.setSynchedEvents(sel);
+ CPPUNIT_ASSERT_EQUAL(
+ ByteVector("ETCO" // Frame ID
+ "\x00\x00\x00\x0b" // Frame size
+ "\x00\x00" // Frame flags
+ "\x02" // Time stamp format
+ "\x02" // 1st event
+ "\x00\x00\xf3\x5c" // 1st time stamp
+ "\xfe" // 2nd event
+ "\x00\x36\xee\x80", 21), // 2nd time stamp
+ f.render());
+ }
+
void testItunes24FrameSize()
{
MPEG::File f(TEST_FILE_PATH_C("005411.id3"), false);