Implement 'Length in milliseconds' feature of DSF/EBML.

This commit is contained in:
Tsuda Kageyu 2015-08-10 01:35:57 +09:00
parent ef09a707b8
commit dc0cc4e7fa
5 changed files with 77 additions and 53 deletions

View File

@ -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<uint>((d->samplingFrequency * d->bitsPerSample * d->channelNum) / 1000.0);
d->length
= d->samplingFrequency > 0 ? static_cast<uint>(d->sampleCount / d->samplingFrequency) : 0;
d->bitrate = static_cast<int>(d->samplingFrequency * d->bitsPerSample * d->channelNum / 1000.0 + 0.5);
if(d->samplingFrequency > 0)
d->length = static_cast<int>(d->sampleCount * 1000.0 / d->samplingFrequency + 0.5);
}

View File

@ -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<int>(value->getAsFloat() / 1000000000.L);
if((value = info->getChild(Constants::TimecodeScale)))
length *= static_cast<int>(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<int>(8 * document->tell() / ((length > 0) ? length : 1));
if((value = info->getChild(Constants::Channels)))
channels = static_cast<int>(value->getAsUnsigned());
if((value = info->getChild(Constants::SamplingFrequency)))
samplerate = static_cast<int>(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<int>(length * value->getAsUnsigned() + 0.5);
else
d->length = static_cast<int>(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<int>(document->length() * 8.0 / d->length + 0.5);
if((value = info->getChild(Constants::Channels)))
d->channels = static_cast<int>(value->getAsUnsigned());
if((value = info->getChild(Constants::SamplingFrequency)))
d->samplerate = static_cast<int>(value->getAsFloat());
}

View File

@ -77,6 +77,8 @@ namespace TagLib {
virtual int sampleRate() const;
private:
void read(File *document);
class AudioPropertiesPrivate;
AudioPropertiesPrivate *d;
};

View File

@ -1,9 +1,9 @@
#include <cppunit/extensions/HelperMacros.h>
#include <string>
#include <stdio.h>
#include <tag.h>
#include <tbytevectorlist.h>
#include <dsffile.h>
#include <cppunit/extensions/HelperMacros.h>
#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()

View File

@ -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());
}
};