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;
// 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()
}
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;
}
// 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;
// *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 "
*/
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;
/*!
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;
Properties(const Properties &);
Properties &operator=(const Properties &);
- void read();
+ void read(File *file);
class PropertiesPrivate;
PropertiesPrivate *d;
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()