1 /***************************************************************************
2     copyright            : (C) 2012 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 "opusproperties.h"
36 #include "opusfile.h"
37 
38 using namespace TagLib;
39 using namespace TagLib::Ogg;
40 
41 class Opus::Properties::PropertiesPrivate
42 {
43 public:
PropertiesPrivate()44   PropertiesPrivate() :
45     length(0),
46     bitrate(0),
47     inputSampleRate(0),
48     channels(0),
49     opusVersion(0) {}
50 
51   int length;
52   int bitrate;
53   int inputSampleRate;
54   int channels;
55   int opusVersion;
56 };
57 
58 ////////////////////////////////////////////////////////////////////////////////
59 // public members
60 ////////////////////////////////////////////////////////////////////////////////
61 
Properties(File * file,ReadStyle style)62 Opus::Properties::Properties(File *file, ReadStyle style) :
63   AudioProperties(style),
64   d(new PropertiesPrivate())
65 {
66   read(file);
67 }
68 
~Properties()69 Opus::Properties::~Properties()
70 {
71   delete d;
72 }
73 
length() const74 int Opus::Properties::length() const
75 {
76   return lengthInSeconds();
77 }
78 
lengthInSeconds() const79 int Ogg::Opus::Properties::lengthInSeconds() const
80 {
81   return d->length / 1000;
82 }
83 
lengthInMilliseconds() const84 int Ogg::Opus::Properties::lengthInMilliseconds() const
85 {
86   return d->length;
87 }
88 
bitrate() const89 int Opus::Properties::bitrate() const
90 {
91   return d->bitrate;
92 }
93 
sampleRate() const94 int Opus::Properties::sampleRate() const
95 {
96   // Opus can decode any stream at a sample rate of 8, 12, 16, 24, or 48 kHz,
97   // so there is no single sample rate. Let's assume it's the highest
98   // possible.
99   return 48000;
100 }
101 
channels() const102 int Opus::Properties::channels() const
103 {
104   return d->channels;
105 }
106 
inputSampleRate() const107 int Opus::Properties::inputSampleRate() const
108 {
109   return d->inputSampleRate;
110 }
111 
opusVersion() const112 int Opus::Properties::opusVersion() const
113 {
114   return d->opusVersion;
115 }
116 
117 ////////////////////////////////////////////////////////////////////////////////
118 // private members
119 ////////////////////////////////////////////////////////////////////////////////
120 
read(File * file)121 void Opus::Properties::read(File *file)
122 {
123   // Get the identification header from the Ogg implementation.
124 
125   // http://tools.ietf.org/html/draft-terriberry-oggopus-01#section-5.1
126 
127   const ByteVector data = file->packet(0);
128 
129   // *Magic Signature*
130   unsigned int pos = 8;
131 
132   // *Version* (8 bits, unsigned)
133   d->opusVersion = static_cast<unsigned char>(data.at(pos));
134   pos += 1;
135 
136   // *Output Channel Count* 'C' (8 bits, unsigned)
137   d->channels = static_cast<unsigned char>(data.at(pos));
138   pos += 1;
139 
140   // *Pre-skip* (16 bits, unsigned, little endian)
141   const unsigned short preSkip = data.toUShort(pos, false);
142   pos += 2;
143 
144   // *Input Sample Rate* (32 bits, unsigned, little endian)
145   d->inputSampleRate = data.toUInt(pos, false);
146   pos += 4;
147 
148   // *Output Gain* (16 bits, signed, little endian)
149   pos += 2;
150 
151   // *Channel Mapping Family* (8 bits, unsigned)
152   pos += 1;
153 
154   const Ogg::PageHeader *first = file->firstPageHeader();
155   const Ogg::PageHeader *last  = file->lastPageHeader();
156 
157   if(first && last) {
158     const long long start = first->absoluteGranularPosition();
159     const long long end   = last->absoluteGranularPosition();
160 
161     if(start >= 0 && end >= 0) {
162       const long long frameCount = (end - start - preSkip);
163 
164       if(frameCount > 0) {
165         const double length = frameCount * 1000.0 / 48000.0;
166         d->length  = static_cast<int>(length + 0.5);
167         d->bitrate = static_cast<int>(file->length() * 8.0 / length + 0.5);
168       }
169     }
170     else {
171       debug("Opus::Properties::read() -- The PCM values for the start or "
172             "end of this file was incorrect.");
173     }
174   }
175   else
176     debug("Opus::Properties::read() -- Could not find valid first and last Ogg pages.");
177 }
178