1 /***************************************************************************
2 copyright : (C) 2006 by Lukáš Lalinský
3 email : lalinsky@gmail.com
4
5 copyright : (C) 2002 - 2008 by Scott Wheeler
6 email : wheeler@kde.org
7 (original Vorbis implementation)
8 ***************************************************************************/
9
10 /***************************************************************************
11 * This library is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU Lesser General Public License version *
13 * 2.1 as published by the Free Software Foundation. *
14 * *
15 * This library is distributed in the hope that it will be useful, but *
16 * WITHOUT ANY WARRANTY; without even the implied warranty of *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
18 * Lesser General Public License for more details. *
19 * *
20 * You should have received a copy of the GNU Lesser General Public *
21 * License along with this library; if not, write to the Free Software *
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
23 * 02110-1301 USA *
24 * *
25 * Alternatively, this file is available under the Mozilla Public *
26 * License Version 1.1. You may obtain a copy of the License at *
27 * http://www.mozilla.org/MPL/ *
28 ***************************************************************************/
29
30 #include <tstring.h>
31 #include <tdebug.h>
32
33 #include <oggpageheader.h>
34
35 #include "speexproperties.h"
36 #include "speexfile.h"
37
38 using namespace TagLib;
39 using namespace TagLib::Ogg;
40
41 class Speex::Properties::PropertiesPrivate
42 {
43 public:
PropertiesPrivate()44 PropertiesPrivate() :
45 length(0),
46 bitrate(0),
47 bitrateNominal(0),
48 sampleRate(0),
49 channels(0),
50 speexVersion(0),
51 vbr(false),
52 mode(0) {}
53
54 int length;
55 int bitrate;
56 int bitrateNominal;
57 int sampleRate;
58 int channels;
59 int speexVersion;
60 bool vbr;
61 int mode;
62 };
63
64 ////////////////////////////////////////////////////////////////////////////////
65 // public members
66 ////////////////////////////////////////////////////////////////////////////////
67
Properties(File * file,ReadStyle style)68 Speex::Properties::Properties(File *file, ReadStyle style) :
69 AudioProperties(style),
70 d(new PropertiesPrivate())
71 {
72 read(file);
73 }
74
~Properties()75 Speex::Properties::~Properties()
76 {
77 delete d;
78 }
79
length() const80 int Speex::Properties::length() const
81 {
82 return lengthInSeconds();
83 }
84
lengthInSeconds() const85 int Speex::Properties::lengthInSeconds() const
86 {
87 return d->length / 1000;
88 }
89
lengthInMilliseconds() const90 int Speex::Properties::lengthInMilliseconds() const
91 {
92 return d->length;
93 }
94
bitrate() const95 int Speex::Properties::bitrate() const
96 {
97 return d->bitrate;
98 }
99
bitrateNominal() const100 int Speex::Properties::bitrateNominal() const
101 {
102 return d->bitrateNominal;
103 }
104
sampleRate() const105 int Speex::Properties::sampleRate() const
106 {
107 return d->sampleRate;
108 }
109
channels() const110 int Speex::Properties::channels() const
111 {
112 return d->channels;
113 }
114
speexVersion() const115 int Speex::Properties::speexVersion() const
116 {
117 return d->speexVersion;
118 }
119
120 ////////////////////////////////////////////////////////////////////////////////
121 // private members
122 ////////////////////////////////////////////////////////////////////////////////
123
read(File * file)124 void Speex::Properties::read(File *file)
125 {
126 // Get the identification header from the Ogg implementation.
127
128 const ByteVector data = file->packet(0);
129 if(data.size() < 64) {
130 debug("Speex::Properties::read() -- data is too short.");
131 return;
132 }
133
134 unsigned int pos = 28;
135
136 // speex_version_id; /**< Version for Speex (for checking compatibility) */
137 d->speexVersion = data.toUInt(pos, false);
138 pos += 4;
139
140 // header_size; /**< Total size of the header ( sizeof(SpeexHeader) ) */
141 pos += 4;
142
143 // rate; /**< Sampling rate used */
144 d->sampleRate = data.toUInt(pos, false);
145 pos += 4;
146
147 // mode; /**< Mode used (0 for narrowband, 1 for wideband) */
148 d->mode = data.toUInt(pos, false);
149 pos += 4;
150
151 // mode_bitstream_version; /**< Version ID of the bit-stream */
152 pos += 4;
153
154 // nb_channels; /**< Number of channels encoded */
155 d->channels = data.toUInt(pos, false);
156 pos += 4;
157
158 // bitrate; /**< Bit-rate used */
159 d->bitrateNominal = data.toUInt(pos, false);
160 pos += 4;
161
162 // frame_size; /**< Size of frames */
163 // unsigned int frameSize = data.mid(pos, 4).toUInt(false);
164 pos += 4;
165
166 // vbr; /**< 1 for a VBR encoding, 0 otherwise */
167 d->vbr = data.toUInt(pos, false) == 1;
168 pos += 4;
169
170 // frames_per_packet; /**< Number of frames stored per Ogg packet */
171 // unsigned int framesPerPacket = data.mid(pos, 4).toUInt(false);
172
173 const Ogg::PageHeader *first = file->firstPageHeader();
174 const Ogg::PageHeader *last = file->lastPageHeader();
175
176 if(first && last) {
177 const long long start = first->absoluteGranularPosition();
178 const long long end = last->absoluteGranularPosition();
179
180 if(start >= 0 && end >= 0 && d->sampleRate > 0) {
181 const long long frameCount = end - start;
182
183 if(frameCount > 0) {
184 const double length = frameCount * 1000.0 / d->sampleRate;
185 long fileLengthWithoutOverhead = file->length();
186 // Ignore the two header packets, see "Ogg file format" in
187 // https://www.speex.org/docs/manual/speex-manual/node8.html
188 for (unsigned int i = 0; i < 2; ++i) {
189 fileLengthWithoutOverhead -= file->packet(i).size();
190 }
191 d->length = static_cast<int>(length + 0.5);
192 d->bitrate = static_cast<int>(fileLengthWithoutOverhead * 8.0 / length + 0.5);
193 }
194 }
195 else {
196 debug("Speex::Properties::read() -- Either the PCM values for the start or "
197 "end of this file was incorrect or the sample rate is zero.");
198 }
199 }
200 else
201 debug("Speex::Properties::read() -- Could not find valid first and last Ogg pages.");
202
203 // Alternative to the actual average bitrate.
204
205 if(d->bitrate == 0 && d->bitrateNominal > 0)
206 d->bitrate = static_cast<int>(d->bitrateNominal / 1000.0 + 0.5);
207 }
208