1 /***************************************************************************
2     copyright            : (C) 2002 - 2008 by Scott Wheeler
3     email                : wheeler@kde.org
4  ***************************************************************************/
5 
6 /***************************************************************************
7  *   This library is free software; you can redistribute it and/or modify  *
8  *   it under the terms of the GNU Lesser General Public License version   *
9  *   2.1 as published by the Free Software Foundation.                     *
10  *                                                                         *
11  *   This library is distributed in the hope that it will be useful, but   *
12  *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
14  *   Lesser General Public License for more details.                       *
15  *                                                                         *
16  *   You should have received a copy of the GNU Lesser General Public      *
17  *   License along with this library; if not, write to the Free Software   *
18  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA         *
19  *   02110-1301  USA                                                       *
20  *                                                                         *
21  *   Alternatively, this file is available under the Mozilla Public        *
22  *   License Version 1.1.  You may obtain a copy of the License at         *
23  *   http://www.mozilla.org/MPL/                                           *
24  ***************************************************************************/
25 
26 #include <tstring.h>
27 #include <tdebug.h>
28 
29 #include <oggpageheader.h>
30 
31 #include "vorbisproperties.h"
32 #include "vorbisfile.h"
33 
34 using namespace TagLib;
35 
36 class Vorbis::Properties::PropertiesPrivate
37 {
38 public:
PropertiesPrivate()39   PropertiesPrivate() :
40     length(0),
41     bitrate(0),
42     sampleRate(0),
43     channels(0),
44     vorbisVersion(0),
45     bitrateMaximum(0),
46     bitrateNominal(0),
47     bitrateMinimum(0) {}
48 
49   int length;
50   int bitrate;
51   int sampleRate;
52   int channels;
53   int vorbisVersion;
54   int bitrateMaximum;
55   int bitrateNominal;
56   int bitrateMinimum;
57 };
58 
59 namespace TagLib {
60   /*!
61    * Vorbis headers can be found with one type ID byte and the string "vorbis" in
62    * an Ogg stream.  0x01 indicates the setup header.
63    */
64   static const char vorbisSetupHeaderID[] = { 0x01, 'v', 'o', 'r', 'b', 'i', 's', 0 };
65 }
66 
67 ////////////////////////////////////////////////////////////////////////////////
68 // public members
69 ////////////////////////////////////////////////////////////////////////////////
70 
Properties(File * file,ReadStyle style)71 Vorbis::Properties::Properties(File *file, ReadStyle style) :
72   AudioProperties(style),
73   d(new PropertiesPrivate())
74 {
75   read(file);
76 }
77 
~Properties()78 Vorbis::Properties::~Properties()
79 {
80   delete d;
81 }
82 
length() const83 int Vorbis::Properties::length() const
84 {
85   return lengthInSeconds();
86 }
87 
lengthInSeconds() const88 int Vorbis::Properties::lengthInSeconds() const
89 {
90   return d->length / 1000;
91 }
92 
lengthInMilliseconds() const93 int Vorbis::Properties::lengthInMilliseconds() const
94 {
95   return d->length;
96 }
97 
bitrate() const98 int Vorbis::Properties::bitrate() const
99 {
100   return d->bitrate;
101 }
102 
sampleRate() const103 int Vorbis::Properties::sampleRate() const
104 {
105   return d->sampleRate;
106 }
107 
channels() const108 int Vorbis::Properties::channels() const
109 {
110   return d->channels;
111 }
112 
vorbisVersion() const113 int Vorbis::Properties::vorbisVersion() const
114 {
115   return d->vorbisVersion;
116 }
117 
bitrateMaximum() const118 int Vorbis::Properties::bitrateMaximum() const
119 {
120   return d->bitrateMaximum;
121 }
122 
bitrateNominal() const123 int Vorbis::Properties::bitrateNominal() const
124 {
125   return d->bitrateNominal;
126 }
127 
bitrateMinimum() const128 int Vorbis::Properties::bitrateMinimum() const
129 {
130   return d->bitrateMinimum;
131 }
132 
133 ////////////////////////////////////////////////////////////////////////////////
134 // private members
135 ////////////////////////////////////////////////////////////////////////////////
136 
read(File * file)137 void Vorbis::Properties::read(File *file)
138 {
139   // Get the identification header from the Ogg implementation.
140 
141   const ByteVector data = file->packet(0);
142   if(data.size() < 28) {
143     debug("Vorbis::Properties::read() -- data is too short.");
144     return;
145   }
146 
147   unsigned int pos = 0;
148 
149   if(data.mid(pos, 7) != vorbisSetupHeaderID) {
150     debug("Vorbis::Properties::read() -- invalid Vorbis identification header");
151     return;
152   }
153 
154   pos += 7;
155 
156   d->vorbisVersion = data.toUInt(pos, false);
157   pos += 4;
158 
159   d->channels = static_cast<unsigned char>(data[pos]);
160   pos += 1;
161 
162   d->sampleRate = data.toUInt(pos, false);
163   pos += 4;
164 
165   d->bitrateMaximum = data.toUInt(pos, false);
166   pos += 4;
167 
168   d->bitrateNominal = data.toUInt(pos, false);
169   pos += 4;
170 
171   d->bitrateMinimum = data.toUInt(pos, false);
172   pos += 4;
173 
174   // Find the length of the file.  See http://wiki.xiph.org/VorbisStreamLength/
175   // for my notes on the topic.
176 
177   const Ogg::PageHeader *first = file->firstPageHeader();
178   const Ogg::PageHeader *last  = file->lastPageHeader();
179 
180   if(first && last) {
181     const long long start = first->absoluteGranularPosition();
182     const long long end   = last->absoluteGranularPosition();
183 
184     if(start >= 0 && end >= 0 && d->sampleRate > 0) {
185       const long long frameCount = end - start;
186 
187       if(frameCount > 0) {
188         const double length = frameCount * 1000.0 / d->sampleRate;
189 
190         d->length  = static_cast<int>(length + 0.5);
191         d->bitrate = static_cast<int>(file->length() * 8.0 / length + 0.5);
192       }
193     }
194     else {
195       debug("Vorbis::Properties::read() -- Either the PCM values for the start or "
196             "end of this file was incorrect or the sample rate is zero.");
197     }
198   }
199   else
200     debug("Vorbis::Properties::read() -- Could not find valid first and last Ogg pages.");
201 
202   // Alternative to the actual average bitrate.
203 
204   if(d->bitrate == 0 && d->bitrateNominal > 0)
205     d->bitrate = static_cast<int>(d->bitrateNominal / 1000.0 + 0.5);
206 }
207