class MP4::Properties::PropertiesPrivate
{
public:
- PropertiesPrivate() : length(0), bitrate(0), sampleRate(0), channels(0), bitsPerSample(0), encrypted(false), codec(MP4::Properties::Unknown) {}
+ PropertiesPrivate() :
+ length(0),
+ bitrate(0),
+ sampleRate(0),
+ channels(0),
+ bitsPerSample(0),
+ encrypted(false),
+ codec(MP4::Properties::Unknown) {}
int length;
int bitrate;
Codec codec;
};
-MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style)
- : AudioProperties(style)
+////////////////////////////////////////////////////////////////////////////////
+// public members
+////////////////////////////////////////////////////////////////////////////////
+
+MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style) :
+ AudioProperties(style),
+ d(new PropertiesPrivate())
+{
+ read(file, atoms);
+}
+
+MP4::Properties::~Properties()
+{
+ delete d;
+}
+
+int
+MP4::Properties::channels() const
+{
+ return d->channels;
+}
+
+int
+MP4::Properties::sampleRate() const
+{
+ return d->sampleRate;
+}
+
+int
+MP4::Properties::length() const
+{
+ return lengthInSeconds();
+}
+
+int
+MP4::Properties::lengthInSeconds() const
+{
+ return d->length / 1000;
+}
+
+int
+MP4::Properties::lengthInMilliseconds() const
+{
+ return d->length;
+}
+
+int
+MP4::Properties::bitrate() const
+{
+ return d->bitrate;
+}
+
+int
+MP4::Properties::bitsPerSample() const
+{
+ return d->bitsPerSample;
+}
+
+bool
+MP4::Properties::isEncrypted() const
+{
+ return d->encrypted;
+}
+
+MP4::Properties::Codec
+MP4::Properties::codec() const
{
- d = new PropertiesPrivate;
+ return d->codec;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// private members
+////////////////////////////////////////////////////////////////////////////////
+void
+MP4::Properties::read(File *file, Atoms *atoms)
+{
MP4::Atom *moov = atoms->find("moov");
if(!moov) {
debug("MP4: Atom 'moov' not found");
MP4::Atom *trak = 0;
ByteVector data;
- MP4::AtomList trakList = moov->findall("trak");
- for (unsigned int i = 0; i < trakList.size(); i++) {
- trak = trakList[i];
+ const MP4::AtomList trakList = moov->findall("trak");
+ for(MP4::AtomList::ConstIterator it = trakList.begin(); it != trakList.end(); ++it) {
+ trak = *it;
MP4::Atom *hdlr = trak->find("mdia", "hdlr");
if(!hdlr) {
debug("MP4: Atom 'trak.mdia.hdlr' not found");
}
trak = 0;
}
- if (!trak) {
+ if(!trak) {
debug("MP4: No audio tracks");
return;
}
file->seek(mdhd->offset);
data = file->readBlock(mdhd->length);
- uint version = data[8];
+
+ const uint version = data[8];
+ long long unit;
+ long long length;
if(version == 1) {
- if (data.size() < 36 + 8) {
+ if(data.size() < 36 + 8) {
debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
return;
}
- const long long unit = data.toLongLong(28U);
- const long long length = data.toLongLong(36U);
- d->length = unit ? int(length / unit) : 0;
+ unit = data.toLongLong(28U);
+ length = data.toLongLong(36U);
}
else {
- if (data.size() < 24 + 4) {
+ if(data.size() < 24 + 4) {
debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
return;
}
- const unsigned int unit = data.toUInt(20U);
- const unsigned int length = data.toUInt(24U);
- d->length = unit ? length / unit : 0;
+ unit = data.toUInt(20U);
+ length = data.toUInt(24U);
}
+ if(unit > 0 && length > 0)
+ d->length = static_cast<int>(length * 1000.0 / unit);
MP4::Atom *atom = trak->find("mdia", "minf", "stbl", "stsd");
if(!atom) {
}
}
}
- else if (data.mid(20, 4) == "alac") {
+ else if(data.mid(20, 4) == "alac") {
if (atom->length == 88 && data.mid(56, 4) == "alac") {
d->codec = ALAC;
d->bitsPerSample = data.at(69);
d->encrypted = true;
}
}
-
-MP4::Properties::~Properties()
-{
- delete d;
-}
-
-int
-MP4::Properties::channels() const
-{
- return d->channels;
-}
-
-int
-MP4::Properties::sampleRate() const
-{
- return d->sampleRate;
-}
-
-int
-MP4::Properties::length() const
-{
- return d->length;
-}
-
-int
-MP4::Properties::bitrate() const
-{
- return d->bitrate;
-}
-
-int
-MP4::Properties::bitsPerSample() const
-{
- return d->bitsPerSample;
-}
-
-bool
-MP4::Properties::isEncrypted() const
-{
- return d->encrypted;
-}
-
-MP4::Properties::Codec MP4::Properties::codec() const
-{
- return d->codec;
-}
-
Properties(File *file, Atoms *atoms, ReadStyle style = Average);
virtual ~Properties();
+ /*!
+ * Returns the length of the file in seconds. The length is rounded down to
+ * the nearest whole second.
+ *
+ * \note This method is just an alias of lengthInSeconds().
+ *
+ * \deprecated
+ */
virtual int length() const;
+
+ /*!
+ * Returns the length of the file in seconds. The length is rounded down to
+ * the nearest whole second.
+ *
+ * \see lengthInMilliseconds()
+ */
+ // BIC: make virtual
+ int lengthInSeconds() const;
+
+ /*!
+ * Returns the length of the file in milliseconds.
+ *
+ * \see lengthInSeconds()
+ */
+ // BIC: make virtual
+ int lengthInMilliseconds() const;
+
+ /*!
+ * Returns the average bit rate of the file in kb/s.
+ */
virtual int bitrate() const;
+
+ /*!
+ * Returns the sample rate in Hz.
+ */
virtual int sampleRate() const;
+
+ /*!
+ * Returns the number of audio channels.
+ */
virtual int channels() const;
+
+ /*!
+ * Returns the number of bits per audio sample.
+ */
virtual int bitsPerSample() const;
+
+ /*!
+ * Returns whether or not the file is encrypted.
+ */
bool isEncrypted() const;
- //! Audio codec used in the MP4 file
+ /*!
+ * Returns the codec used in the file.
+ */
Codec codec() const;
private:
+ void read(File *file, Atoms *atoms);
+
class PropertiesPrivate;
PropertiesPrivate *d;
};
void testPropertiesAAC()
{
MP4::File f(TEST_FILE_PATH_C("has-tags.m4a"));
+ CPPUNIT_ASSERT(f.audioProperties());
CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->length());
+ CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds());
+ CPPUNIT_ASSERT_EQUAL(3707, f.audioProperties()->lengthInMilliseconds());
CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->bitrate());
CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels());
CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate());
- CPPUNIT_ASSERT_EQUAL(16, ((MP4::Properties *)f.audioProperties())->bitsPerSample());
- CPPUNIT_ASSERT_EQUAL(MP4::Properties::AAC, ((MP4::Properties *)f.audioProperties())->codec());
+ CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample());
+ CPPUNIT_ASSERT_EQUAL(false, f.audioProperties()->isEncrypted());
+ CPPUNIT_ASSERT_EQUAL(MP4::Properties::AAC, f.audioProperties()->codec());
}
void testPropertiesALAC()
{
MP4::File f(TEST_FILE_PATH_C("empty_alac.m4a"));
+ CPPUNIT_ASSERT(f.audioProperties());
CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->length());
+ CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds());
+ CPPUNIT_ASSERT_EQUAL(3705, f.audioProperties()->lengthInMilliseconds());
CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->bitrate());
CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels());
CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate());
- CPPUNIT_ASSERT_EQUAL(16, ((MP4::Properties *)f.audioProperties())->bitsPerSample());
- CPPUNIT_ASSERT_EQUAL(MP4::Properties::ALAC, ((MP4::Properties *)f.audioProperties())->codec());
+ CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample());
+ CPPUNIT_ASSERT_EQUAL(false, f.audioProperties()->isEncrypted());
+ CPPUNIT_ASSERT_EQUAL(MP4::Properties::ALAC, f.audioProperties()->codec());
}
void testCheckValid()