]> granicus.if.org Git - taglib/commitdiff
Ogg Vorbis: AudioProperties improvements
authorTsuda Kageyu <tsuda.kageyu@gmail.com>
Thu, 21 May 2015 06:12:31 +0000 (15:12 +0900)
committerTsuda Kageyu <tsuda.kageyu@gmail.com>
Thu, 18 Jun 2015 08:24:31 +0000 (17:24 +0900)
Add lengthInSeconds(), lengthInMilliseconds() properties. (#503)
Remove some data members which are not needed to carry.
Add some tests for audio properties.
Add some supplementary comments.

taglib/ogg/vorbis/vorbisproperties.cpp
taglib/ogg/vorbis/vorbisproperties.h
tests/test_ogg.cpp

index b5e88bfd0063b9c07a9ffd33cf25c33e7eb5738e..d9dfc0a89e916607664b0868b7590d5a59e0efeb 100644 (file)
@@ -36,9 +36,7 @@ using namespace TagLib;
 class Vorbis::Properties::PropertiesPrivate
 {
 public:
-  PropertiesPrivate(File *f, ReadStyle s) :
-    file(f),
-    style(s),
+  PropertiesPrivate() :
     length(0),
     bitrate(0),
     sampleRate(0),
@@ -48,8 +46,6 @@ public:
     bitrateNominal(0),
     bitrateMinimum(0) {}
 
-  File *file;
-  ReadStyle style;
   int length;
   int bitrate;
   int sampleRate;
@@ -72,10 +68,11 @@ namespace TagLib {
 // public members
 ////////////////////////////////////////////////////////////////////////////////
 
-Vorbis::Properties::Properties(File *file, ReadStyle style) : AudioProperties(style)
+Vorbis::Properties::Properties(File *file, ReadStyle style) :
+  AudioProperties(style),
+  d(new PropertiesPrivate())
 {
-  d = new PropertiesPrivate(file, style);
-  read();
+  read(file);
 }
 
 Vorbis::Properties::~Properties()
@@ -84,13 +81,23 @@ Vorbis::Properties::~Properties()
 }
 
 int Vorbis::Properties::length() const
+{
+  return lengthInSeconds();
+}
+
+int Vorbis::Properties::lengthInSeconds() const
+{
+  return d->length / 1000;
+}
+
+int Vorbis::Properties::lengthInMilliseconds() const
 {
   return d->length;
 }
 
 int Vorbis::Properties::bitrate() const
 {
-  return int(float(d->bitrate) / float(1000) + 0.5);
+  return d->bitrate;
 }
 
 int Vorbis::Properties::sampleRate() const
@@ -127,11 +134,15 @@ int Vorbis::Properties::bitrateMinimum() const
 // private members
 ////////////////////////////////////////////////////////////////////////////////
 
-void Vorbis::Properties::read()
+void Vorbis::Properties::read(File *file)
 {
   // Get the identification header from the Ogg implementation.
 
-  ByteVector data = d->file->packet(0);
+  const ByteVector data = file->packet(0);
+  if(data.size() < 28) {
+    debug("Vorbis::Properties::read() -- data is too short.");
+    return;
+  }
 
   uint pos = 0;
 
@@ -158,26 +169,38 @@ void Vorbis::Properties::read()
   pos += 4;
 
   d->bitrateMinimum = data.toUInt(pos, false);
-
-  // TODO: Later this should be only the "fast" mode.
-  d->bitrate = d->bitrateNominal;
+  pos += 4;
 
   // Find the length of the file.  See http://wiki.xiph.org/VorbisStreamLength/
   // for my notes on the topic.
 
-  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) {
-    long long start = first->absoluteGranularPosition();
-    long long end = last->absoluteGranularPosition();
+    const long long start = first->absoluteGranularPosition();
+    const long long end   = last->absoluteGranularPosition();
+
+    if(start >= 0 && end >= 0 && d->sampleRate > 0) {
+      const long long frameCount = end - start;
 
-    if(start >= 0 && end >= 0 && d->sampleRate > 0)
-      d->length = (int)((end - start) / (long long) d->sampleRate);
-    else
+      if(frameCount > 0) {
+        const double length = frameCount * 1000.0 / d->sampleRate;
+
+        d->length  = static_cast<int>(length + 0.5);
+        d->bitrate = static_cast<int>(file->length() * 8.0 / length + 0.5);
+      }
+    }
+    else {
       debug("Vorbis::Properties::read() -- Either the PCM values for the start or "
             "end of this file was incorrect or the sample rate is zero.");
+    }
   }
   else
     debug("Vorbis::Properties::read() -- Could not find valid first and last Ogg pages.");
+
+  // Alternative to the actual average bitrate.
+
+  if(d->bitrate == 0 && d->bitrateNominal > 0)
+    d->bitrate = static_cast<int>(d->bitrateNominal / 1000.0 + 0.5);
 }
index de46985b68c54934d7c1715b8c18638f3e86c7a3..9da0ac9d791f82ce8e1fc9d8050298efd5b86724 100644 (file)
@@ -67,11 +67,46 @@ 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.
+       */
       virtual int sampleRate() const;
+
+      /*!
+       * Returns the number of audio channels.
+       */
       virtual int channels() const;
 
       /*!
@@ -101,7 +136,7 @@ namespace TagLib {
       Properties(const Properties &);
       Properties &operator=(const Properties &);
 
-      void read();
+      void read(File *file);
 
       class PropertiesPrivate;
       PropertiesPrivate *d;
index 8d69371ef61f2730e0940d2197041040660c1fef..f5f27bbcaa7747c14074181e144b555e4d1b2dc0 100644 (file)
@@ -20,6 +20,7 @@ class TestOGG : public CppUnit::TestFixture
   CPPUNIT_TEST(testSplitPackets);
   CPPUNIT_TEST(testDictInterface1);
   CPPUNIT_TEST(testDictInterface2);
+  CPPUNIT_TEST(testAudioProperties);
   CPPUNIT_TEST_SUITE_END();
 
 public:
@@ -104,6 +105,21 @@ public:
     delete f;
   }
 
+  void testAudioProperties()
+  {
+    Ogg::Vorbis::File f(TEST_FILE_PATH_C("empty.ogg"));
+    CPPUNIT_ASSERT(f.audioProperties());
+    CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->length());
+    CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds());
+    CPPUNIT_ASSERT_EQUAL(3685, f.audioProperties()->lengthInMilliseconds());
+    CPPUNIT_ASSERT_EQUAL(9, f.audioProperties()->bitrate());
+    CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels());
+    CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate());
+    CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->vorbisVersion());
+    CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrateMaximum());
+    CPPUNIT_ASSERT_EQUAL(112000, f.audioProperties()->bitrateNominal());
+    CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrateMinimum());
+  }
 };
 
 CPPUNIT_TEST_SUITE_REGISTRATION(TestOGG);