Skip to content
Permalink
Browse files

Merge pull request #561 from TsudaKageyu/audioprop-opus

(wishlist) Ogg Opus: AudioProperties improvements
  • Loading branch information...
TsudaKageyu committed Jul 31, 2015
2 parents 6a77875 + f729f86 commit 8b1e872f819537e79a7bb2b346d23f8e22e01c81
@@ -59,20 +59,20 @@ class Opus::File::FilePrivate
// public members
////////////////////////////////////////////////////////////////////////////////

Opus::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle) :
Opus::File::File(FileName file, bool readProperties, Properties::ReadStyle) :
Ogg::File(file),
d(new FilePrivate())
{
if(isOpen())
read(readProperties, propertiesStyle);
read(readProperties);
}

Opus::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle propertiesStyle) :
Opus::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle) :
Ogg::File(stream),
d(new FilePrivate())
{
if(isOpen())
read(readProperties, propertiesStyle);
read(readProperties);
}

Opus::File::~File()
@@ -114,7 +114,7 @@ bool Opus::File::save()
// private members
////////////////////////////////////////////////////////////////////////////////

void Opus::File::read(bool readProperties, Properties::ReadStyle propertiesStyle)
void Opus::File::read(bool readProperties)
{
ByteVector opusHeaderData = packet(0);

@@ -135,5 +135,5 @@ void Opus::File::read(bool readProperties, Properties::ReadStyle propertiesStyle
d->comment = new Ogg::XiphComment(commentHeaderData.mid(8));

if(readProperties)
d->properties = new Properties(this, propertiesStyle);
d->properties = new Properties(this);
}
@@ -112,7 +112,7 @@ namespace TagLib {
File(const File &);
File &operator=(const File &);

void read(bool readProperties, Properties::ReadStyle propertiesStyle);
void read(bool readProperties);

class FilePrivate;
FilePrivate *d;
@@ -41,17 +41,13 @@ using namespace TagLib::Ogg;
class Opus::Properties::PropertiesPrivate
{
public:
PropertiesPrivate(File *f, ReadStyle s) :
file(f),
style(s),
PropertiesPrivate() :
length(0),
bitrate(0),
inputSampleRate(0),
channels(0),
opusVersion(0) {}

File *file;
ReadStyle style;
int length;
int bitrate;
int inputSampleRate;
@@ -63,10 +59,11 @@ class Opus::Properties::PropertiesPrivate
// public members
////////////////////////////////////////////////////////////////////////////////

Opus::Properties::Properties(File *file, ReadStyle style) : AudioProperties(style)
Opus::Properties::Properties(File *file, ReadStyle style) :
AudioProperties(style),
d(new PropertiesPrivate())
{
d = new PropertiesPrivate(file, style);
read();
read(file);
}

Opus::Properties::~Properties()
@@ -75,6 +72,16 @@ Opus::Properties::~Properties()
}

int Opus::Properties::length() const
{
return lengthInSeconds();
}

int Ogg::Opus::Properties::lengthInSeconds() const
{
return d->length / 1000;
}

int Ogg::Opus::Properties::lengthInMilliseconds() const
{
return d->length;
}
@@ -111,13 +118,13 @@ int Opus::Properties::opusVersion() const
// private members
////////////////////////////////////////////////////////////////////////////////

void Opus::Properties::read()
void Opus::Properties::read(File *file)
{
// Get the identification header from the Ogg implementation.

// http://tools.ietf.org/html/draft-terriberry-oggopus-01#section-5.1

ByteVector data = d->file->packet(0);
const ByteVector data = file->packet(0);

// *Magic Signature*
uint pos = 8;
@@ -144,16 +151,21 @@ void Opus::Properties::read()
// *Channel Mapping Family* (8 bits, unsigned)
pos += 1;

const Ogg::PageHeader *first = d->file->firstPageHeader();
const Ogg::PageHeader *last = d->file->lastPageHeader();
const Ogg::PageHeader *first = file->firstPageHeader();
const Ogg::PageHeader *last = file->lastPageHeader();

if(first && last) {
const long long start = first->absoluteGranularPosition();
const long long end = last->absoluteGranularPosition();

if(start >= 0 && end >= 0) {
d->length = (int)((end - start - preSkip) / 48000);
d->bitrate = (int)(d->file->length() * 8.0 / (1000.0 * d->length) + 0.5);
const long long frameCount = (end - start - preSkip);

if(frameCount > 0) {
const double length = frameCount * 1000.0 / 48000.0;
d->length = static_cast<int>(length + 0.5);
d->bitrate = static_cast<int>(file->length() * 8.0 / length + 0.5);
}
}
else {
debug("Opus::Properties::read() -- The PCM values for the start or "
@@ -61,11 +61,49 @@ namespace TagLib {
*/
virtual ~Properties();

// Reimplementations.

/*!
* 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.
*
* \note Always returns 48000, because Opus can decode any stream at a
* sample rate of 8, 12, 16, 24, or 48 kHz,
*/
virtual int sampleRate() const;

/*!
* Returns the number of audio channels.
*/
virtual int channels() const;

/*!
@@ -76,15 +114,15 @@ namespace TagLib {
int inputSampleRate() const;

/*!
* Returns the Opus version, currently "0" (as specified by the spec).
* Returns the Opus version, in the range 0...255.
*/
int opusVersion() const;

private:
Properties(const Properties &);
Properties &operator=(const Properties &);

void read();
void read(File *file);

class PropertiesPrivate;
PropertiesPrivate *d;
@@ -12,21 +12,25 @@ using namespace TagLib;
class TestOpus : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE(TestOpus);
CPPUNIT_TEST(testProperties);
CPPUNIT_TEST(testAudioProperties);
CPPUNIT_TEST(testReadComments);
CPPUNIT_TEST(testWriteComments);
CPPUNIT_TEST_SUITE_END();

public:

void testProperties()
void testAudioProperties()
{
Ogg::Opus::File f(TEST_FILE_PATH_C("correctness_gain_silent_output.opus"));
CPPUNIT_ASSERT(f.audioProperties());
CPPUNIT_ASSERT_EQUAL(7, f.audioProperties()->length());
CPPUNIT_ASSERT_EQUAL(41, f.audioProperties()->bitrate());
CPPUNIT_ASSERT_EQUAL(7, f.audioProperties()->lengthInSeconds());
CPPUNIT_ASSERT_EQUAL(7737, f.audioProperties()->lengthInMilliseconds());
CPPUNIT_ASSERT_EQUAL(37, f.audioProperties()->bitrate());
CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->channels());
CPPUNIT_ASSERT_EQUAL(48000, f.audioProperties()->sampleRate());
CPPUNIT_ASSERT_EQUAL(48000, ((Ogg::Opus::Properties *)f.audioProperties())->inputSampleRate());
CPPUNIT_ASSERT_EQUAL(48000, f.audioProperties()->inputSampleRate());
CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->opusVersion());
}

void testReadComments()

0 comments on commit 8b1e872

Please sign in to comment.
You can’t perform that action at this time.