From dc0cc4e7fadacb67c75a48145e68af56227f0043 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Mon, 10 Aug 2015 01:35:57 +0900 Subject: [PATCH] Implement 'Length in milliseconds' feature of DSF/EBML. --- taglib/dsf/dsfproperties.cpp | 16 ++--- taglib/ebml/matroska/ebmlmatroskaaudio.cpp | 79 ++++++++++++---------- taglib/ebml/matroska/ebmlmatroskaaudio.h | 2 + tests/test_dsf.cpp | 19 ++++-- tests/test_matroska.cpp | 14 ++-- 5 files changed, 77 insertions(+), 53 deletions(-) diff --git a/taglib/dsf/dsfproperties.cpp b/taglib/dsf/dsfproperties.cpp index 498a650b..731e4512 100644 --- a/taglib/dsf/dsfproperties.cpp +++ b/taglib/dsf/dsfproperties.cpp @@ -59,8 +59,8 @@ public: uint blockSizePerChannel; // Computed - uint bitrate; - uint length; + int bitrate; + int length; }; //////////////////////////////////////////////////////////////////////////////// @@ -85,12 +85,12 @@ int DSF::AudioProperties::length() const int DSF::AudioProperties::lengthInSeconds() const { - return d->length; + return d->length / 1000; } int DSF::AudioProperties::lengthInMilliseconds() const { - return d->length * 1000; + return d->length; } int DSF::AudioProperties::bitrate() const @@ -154,8 +154,8 @@ void DSF::AudioProperties::read(const ByteVector &data) d->sampleCount = data.toInt64LE(24); d->blockSizePerChannel = data.toUInt32LE(32); - d->bitrate - = static_cast((d->samplingFrequency * d->bitsPerSample * d->channelNum) / 1000.0); - d->length - = d->samplingFrequency > 0 ? static_cast(d->sampleCount / d->samplingFrequency) : 0; + d->bitrate = static_cast(d->samplingFrequency * d->bitsPerSample * d->channelNum / 1000.0 + 0.5); + + if(d->samplingFrequency > 0) + d->length = static_cast(d->sampleCount * 1000.0 / d->samplingFrequency + 0.5); } diff --git a/taglib/ebml/matroska/ebmlmatroskaaudio.cpp b/taglib/ebml/matroska/ebmlmatroskaaudio.cpp index 8c956776..fd065c6e 100644 --- a/taglib/ebml/matroska/ebmlmatroskaaudio.cpp +++ b/taglib/ebml/matroska/ebmlmatroskaaudio.cpp @@ -32,41 +32,11 @@ class EBML::Matroska::AudioProperties::AudioPropertiesPrivate { public: // Constructor - AudioPropertiesPrivate(File *document) : + AudioPropertiesPrivate() : length(0), bitrate(0), channels(1), - samplerate(8000) - { - Element *elem = document->getDocumentRoot()->getChild(Constants::Segment); - Element *info = elem->getChild(Constants::SegmentInfo); - Element *value; - - if(info && (value = info->getChild(Constants::Duration))) { - length = static_cast(value->getAsFloat() / 1000000000.L); - if((value = info->getChild(Constants::TimecodeScale))) - length *= static_cast(value->getAsUnsigned()); - else - length *= 1000000; - } - - info = elem->getChild(Constants::Tracks); - if(!info || !(info = info->getChild(Constants::TrackEntry)) || - !(info = info->getChild(Constants::Audio))) { - - return; - } - - // Dirty bitrate: - document->seek(0, File::End); - bitrate = static_cast(8 * document->tell() / ((length > 0) ? length : 1)); - - if((value = info->getChild(Constants::Channels))) - channels = static_cast(value->getAsUnsigned()); - - if((value = info->getChild(Constants::SamplingFrequency))) - samplerate = static_cast(value->getAsFloat()); - } + samplerate(8000) {} // The length of the file int length; @@ -86,8 +56,9 @@ public: //////////////////////////////////////////////////////////////////////////////// EBML::Matroska::AudioProperties::AudioProperties(File *document) : - d(new AudioPropertiesPrivate(document)) + d(new AudioPropertiesPrivate()) { + read(document); } EBML::Matroska::AudioProperties::~AudioProperties() @@ -102,12 +73,12 @@ int EBML::Matroska::AudioProperties::length() const int EBML::Matroska::AudioProperties::lengthInSeconds() const { - return d->length; + return d->length / 1000; } int EBML::Matroska::AudioProperties::lengthInMilliseconds() const { - return d->length * 1000; + return d->length; } int EBML::Matroska::AudioProperties::bitrate() const @@ -124,3 +95,41 @@ int EBML::Matroska::AudioProperties::sampleRate() const { return d->samplerate; } + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +void EBML::Matroska::AudioProperties::read(File *document) +{ + Element *elem = document->getDocumentRoot()->getChild(Constants::Segment); + Element *info = elem->getChild(Constants::SegmentInfo); + Element *value; + + if(info && (value = info->getChild(Constants::Duration))) { + + const double length = value->getAsFloat() / 1000000.0; + + if((value = info->getChild(Constants::TimecodeScale))) + d->length = static_cast(length * value->getAsUnsigned() + 0.5); + else + d->length = static_cast(length * 1000000 + 0.5); + } + + info = elem->getChild(Constants::Tracks); + if(!info || !(info = info->getChild(Constants::TrackEntry)) || + !(info = info->getChild(Constants::Audio))) { + + return; + } + + // Dirty bitrate: + if(d->length > 0) + d->bitrate = static_cast(document->length() * 8.0 / d->length + 0.5); + + if((value = info->getChild(Constants::Channels))) + d->channels = static_cast(value->getAsUnsigned()); + + if((value = info->getChild(Constants::SamplingFrequency))) + d->samplerate = static_cast(value->getAsFloat()); +} diff --git a/taglib/ebml/matroska/ebmlmatroskaaudio.h b/taglib/ebml/matroska/ebmlmatroskaaudio.h index 80d5f5cc..f3cdedeb 100644 --- a/taglib/ebml/matroska/ebmlmatroskaaudio.h +++ b/taglib/ebml/matroska/ebmlmatroskaaudio.h @@ -77,6 +77,8 @@ namespace TagLib { virtual int sampleRate() const; private: + void read(File *document); + class AudioPropertiesPrivate; AudioPropertiesPrivate *d; }; diff --git a/tests/test_dsf.cpp b/tests/test_dsf.cpp index 8759ce39..b243b490 100644 --- a/tests/test_dsf.cpp +++ b/tests/test_dsf.cpp @@ -1,9 +1,9 @@ -#include #include #include #include #include #include +#include #include "utils.h" using namespace std; @@ -21,10 +21,19 @@ public: void testBasic() { DSF::File f(TEST_FILE_PATH_C("empty.dsf")); - DSF::AudioProperties *props = f.audioProperties(); - CPPUNIT_ASSERT_EQUAL(2822400, props->sampleRate()); - CPPUNIT_ASSERT_EQUAL(1, props->channels()); - CPPUNIT_ASSERT_EQUAL(1, props->bitsPerSample()); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->length()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(2822, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(2822400, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->formatVersion()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->formatID()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->channelType()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL((long long)0, f.audioProperties()->sampleCount()); + CPPUNIT_ASSERT_EQUAL(4096, f.audioProperties()->blockSizePerChannel()); } void testTags() diff --git a/tests/test_matroska.cpp b/tests/test_matroska.cpp index b3d88c68..e18f3b13 100644 --- a/tests/test_matroska.cpp +++ b/tests/test_matroska.cpp @@ -99,14 +99,18 @@ public: EBML::Matroska::File f(filename.c_str()); CPPUNIT_ASSERT(f.isValid()); - AudioProperties* a = f.audioProperties(); - CPPUNIT_ASSERT(a != 0); + CPPUNIT_ASSERT(f.audioProperties()); // Not a very nice assertion... - CPPUNIT_ASSERT_EQUAL(a->length(), 0); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->length()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(735, f.audioProperties()->lengthInMilliseconds()); + // Bitrate is not nice and thus not tested. - CPPUNIT_ASSERT_EQUAL(a->sampleRate(), 44100); - CPPUNIT_ASSERT_EQUAL(a->channels(), 2); + CPPUNIT_ASSERT_EQUAL(51, f.audioProperties()->bitrate()); + + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); } };