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         d->length  = static_cast<int>(length + 0.5);
186         d->bitrate = static_cast<int>(file->length() * 8.0 / length + 0.5);
187       }
188     }
189     else {
190       debug("Speex::Properties::read() -- Either the PCM values for the start or "
191             "end of this file was incorrect or the sample rate is zero.");
192     }
193   }
194   else
195     debug("Speex::Properties::read() -- Could not find valid first and last Ogg pages.");
196 
197   // Alternative to the actual average bitrate.
198 
199   if(d->bitrate == 0 && d->bitrateNominal > 0)
200     d->bitrate = static_cast<int>(d->bitrateNominal / 1000.0 + 0.5);
201 }
202