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 long fileLengthWithoutOverhead = file->length();
190 // Ignore the three initial header packets, see "1.3.1. Decode Setup" in
191 // https://xiph.org/vorbis/doc/Vorbis_I_spec.html
192 for (unsigned int i = 0; i < 3; ++i) {
193 fileLengthWithoutOverhead -= file->packet(i).size();
194 }
195 d->length = static_cast<int>(length + 0.5);
196 d->bitrate = static_cast<int>(fileLengthWithoutOverhead * 8.0 / length + 0.5);
197 }
198 }
199 else {
200 debug("Vorbis::Properties::read() -- Either the PCM values for the start or "
201 "end of this file was incorrect or the sample rate is zero.");
202 }
203 }
204 else
205 debug("Vorbis::Properties::read() -- Could not find valid first and last Ogg pages.");
206
207 // Alternative to the actual average bitrate.
208
209 if(d->bitrate == 0 && d->bitrateNominal > 0)
210 d->bitrate = static_cast<int>(d->bitrateNominal / 1000.0 + 0.5);
211 }
212