kwave  18.07.70
VorbisDecoder.cpp
Go to the documentation of this file.
1 /*************************************************************************
2  VorbisDecoder.cpp - sub decoder for Vorbis in an Ogg container
3  -------------------
4  begin : Wed Dec 26 2012
5  copyright : (C) 2012 by Thomas Eschenbacher
6  email : Thomas.Eschenbacher@gmx.de
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "config.h"
19 
20 #include <stdlib.h>
21 
22 #include <ogg/ogg.h>
23 #include <vorbis/codec.h>
24 
25 #include <QDate>
26 #include <QIODevice>
27 #include <QString>
28 
29 #include <KLocalizedString>
30 
31 #include "libkwave/Compression.h"
32 #include "libkwave/MessageBox.h"
33 #include "libkwave/MultiWriter.h"
34 #include "libkwave/Sample.h"
35 #include "libkwave/SampleArray.h"
37 #include "libkwave/Utils.h"
38 
39 #include "VorbisDecoder.h"
40 
42 #define DEFAULT_BITRATE 128000
43 
44 //***************************************************************************
46  ogg_sync_state &oy,
47  ogg_stream_state &os,
48  ogg_page& og,
49  ogg_packet& op)
50  :m_source(source), m_stream_start_pos(0), m_samples_written(0),
51  m_oy(oy), m_os(os), m_og(og), m_op(op)
52 {
53 }
54 
55 
56 //***************************************************************************
57 void Kwave::VorbisDecoder::parseTag(Kwave::FileInfo &info, const char *tag,
58  Kwave::FileProperty property)
59 {
60  int count = vorbis_comment_query_count(&m_vc, const_cast<char *>(tag));
61  if (count < 1) return;
62  QString value;
63  for (int i = 0; i < count; ++i) {
64  char *text = vorbis_comment_query(&m_vc, const_cast<char *>(tag), i);
65  if (i) value += _("; ");
66  value += QString::fromUtf8(text);
67  }
68 
69  info.set(property, value);
70 }
71 
72 //***************************************************************************
73 int Kwave::VorbisDecoder::open(QWidget *widget, Kwave::FileInfo &info)
74 {
75  // extract the initial header from the first page and verify that the
76  // Ogg bitstream is in fact Vorbis data
77 
78  // I handle the initial header first instead of just having the code
79  // read all three Vorbis headers at once because reading the initial
80  // header is an easy way to identify a Vorbis bitstream and it's
81  // useful to see that functionality separated out.
82  vorbis_info_init(&m_vi);
83  vorbis_comment_init(&m_vc);
84 
85  if (vorbis_synthesis_headerin(&m_vi, &m_vc, &m_op) < 0) {
86  // error case; not a vorbis header
87  Kwave::MessageBox::error(widget, i18n(
88  "This Ogg bitstream does not contain any Vorbis audio data."));
89  return -1;
90  }
91 
92  // At this point, we're sure we're Vorbis. We've set up the logical
93  // (Ogg) bitstream decoder. Get the comment and codebook headers and
94  // set up the Vorbis decoder
95 
96  // The next two packets in order are the comment and codebook headers.
97  // They're likely large and may span multiple pages. Thus we read
98  // and submit data until we get our two packets, watching that no
99  // pages are missing. If a page is missing, error out; losing a
100  // header page is the only place where missing data is fatal. */
101  unsigned int counter = 0;
102  while (counter < 2) {
103  while(counter < 2) {
104  int result = ogg_sync_pageout(&m_oy, &m_og);
105  if (result == 0) break; // Need more data
106  // Don't complain about missing or corrupt data yet. We'll
107  // catch it at the packet output phase
108  if (result == 1) {
109  // we can ignore any errors here
110  // as they'll also become apparent
111  // at packetout
112  ogg_stream_pagein(&m_os, &m_og);
113  while (counter < 2) {
114  result = ogg_stream_packetout(&m_os, &m_op);
115  if (result == 0) break;
116  if (result < 0) {
117  // Uh oh; data at some point was corrupted or
118  // missing! We can't tolerate that in a header.
119  // Die.
120  Kwave::MessageBox::error(widget, i18n(
121  "Corrupt secondary header. Exiting."));
122  return -1;
123  }
124  vorbis_synthesis_headerin(&m_vi, &m_vc, &m_op);
125  counter++;
126  }
127  }
128  }
129 
130  // no harm in not checking before adding more
131  char *buffer = ogg_sync_buffer(&m_oy, 4096);
132  qint64 bytes = m_source->read(buffer, 4096);
133  if (!bytes && counter < 2) {
134  Kwave::MessageBox::error(widget, i18n(
135  "End of file before finding all Vorbis headers."));
136  return -1;
137  }
138  ogg_sync_wrote(&m_oy, static_cast<long int>(bytes));
139  }
140 
141  // OK, got and parsed all three headers. Initialize the Vorbis
142  // packet->PCM decoder. */
143  vorbis_synthesis_init(&m_vd, &m_vi); // central decode state
144  vorbis_block_init(&m_vd, &m_vb); // local state for most of the decode
145  // so multiple block decodes can
146  // proceed in parallel. We could init
147  // multiple vorbis_block structures
148  // for m_vd here
149 
150  // get the standard properties
151  info.setTracks(m_vi.channels);
152  info.setRate(m_vi.rate);
154  info.set(Kwave::INF_SOURCE, _(m_vc.vendor));
155  if ((m_vi.bitrate_nominal > 0) &&
156  (m_vi.bitrate_nominal < std::numeric_limits<int>::max()))
158  QVariant(Kwave::toInt(m_vi.bitrate_nominal)));
159  if ((m_vi.bitrate_lower > 0) &&
160  (m_vi.bitrate_lower < std::numeric_limits<int>::max()))
162  QVariant(Kwave::toInt(m_vi.bitrate_lower)));
163  if ((m_vi.bitrate_upper > 0) &&
164  (m_vi.bitrate_upper < std::numeric_limits<int>::max()))
166  QVariant(Kwave::toInt(m_vi.bitrate_upper)));
167 
168  // the first comment sometimes is used for the software version
169  {
170  char **ptr = m_vc.user_comments;
171  QString s = _(*ptr);
172  if (s.length() && !s.contains(QLatin1Char('='))) {
173  info.set(Kwave::INF_SOFTWARE, s);
174  qDebug("Bitstream is %d channel, %ldHz", m_vi.channels, m_vi.rate);
175  qDebug("Encoded by: %s\n\n", m_vc.vendor);
176  }
177  }
178 
180  parseTag(info, "DATE", Kwave::INF_CREATION_DATE);
182  QString str_date = QVariant(info.get(
183  Kwave::INF_CREATION_DATE)).toString();
184  QDate date;
185  date = QDate::fromString(str_date, Qt::ISODate);
186  if (!date.isValid()) {
187  int year = str_date.toInt();
188  date.setDate(year, 1, 1);
189  }
190  if (date.isValid()) info.set(Kwave::INF_CREATION_DATE, date);
191  }
192 
193  // parse all other (simple) properties
194  parseTag(info, "TITLE", Kwave::INF_NAME);
195  parseTag(info, "VERSION", Kwave::INF_VERSION);
196  parseTag(info, "ALBUM", Kwave::INF_ALBUM);
197  parseTag(info, "TRACKNUMBER", Kwave::INF_TRACK);
198  parseTag(info, "ARTIST", Kwave::INF_AUTHOR);
199  parseTag(info, "PERFORMER", Kwave::INF_PERFORMER);
200  parseTag(info, "COPYRIGHT", Kwave::INF_COPYRIGHT);
201  parseTag(info, "LICENSE", Kwave::INF_LICENSE);
202  parseTag(info, "ORGANIZATION", Kwave::INF_ORGANIZATION);
203  parseTag(info, "DESCRIPTION", Kwave::INF_SUBJECT);
204  parseTag(info, "GENRE", Kwave::INF_GENRE);
205  parseTag(info, "LOCATION", Kwave::INF_SOURCE);
206  parseTag(info, "CONTACT", Kwave::INF_CONTACT);
207  parseTag(info, "ISRC", Kwave::INF_ISRC);
208  parseTag(info, "ENCODER", Kwave::INF_SOFTWARE);
209  parseTag(info, "VBR_QUALITY", Kwave::INF_VBR_QUALITY);
210 
211  // estimate a length
212  // estimate the length of the file from file size, bitrate, channels
213  if (!m_source->isSequential()) {
214  long int br = -1;
215  if ( (m_vi.bitrate_nominal > 0)) br = m_vi.bitrate_nominal;
216  if ((br < 0) && (m_vi.bitrate_upper > 0)) br = m_vi.bitrate_upper;
217  if ((br < 0) && (m_vi.bitrate_lower > 0)) br = m_vi.bitrate_lower;
218  qint64 file_size = m_source->size();
219  qreal rate = m_vi.rate;
220  qreal seconds = (br > 0) ? (file_size / (br / 8)) :
222  sample_index_t samples = static_cast<sample_index_t>(seconds * rate);
223 
224  qDebug(" estimated length: %llu samples", samples);
225  info.set(Kwave::INF_ESTIMATED_LENGTH, samples);
226  }
227 
228  m_stream_start_pos = m_source->pos();
229 
230  return 1;
231 }
232 
233 //***************************************************************************
234 static inline int decodeFrame(float **pcm, unsigned int size,
235  Kwave::MultiWriter &dest)
236 {
237  const unsigned int tracks = dest.tracks();
238 
239  // convert floats to 16 bit signed ints
240  // (host order) and interleave
241  for (unsigned int track = 0; track < tracks; track++) {
242  float *mono = pcm[track];
243  int bout = size;
244  unsigned int ofs = 0;
245  Kwave::SampleArray buffer(size);
246 
247  while (bout--) {
248  // scale, use some primitive noise shaping + clipping
249  double noise = (drand48() - double(0.5)) / double(SAMPLE_MAX);
250  double d = static_cast<double>(*(mono++));
251  sample_t s = qBound<sample_t>(
252  SAMPLE_MIN, double2sample(d + noise), SAMPLE_MAX
253  );
254 
255  // write the clipped sample to the stream
256  buffer[ofs++] = s;
257  }
258 
259  // write the buffer to the stream
260  *(dest[track]) << buffer;
261  }
262 
263  return size;
264 }
265 
266 //***************************************************************************
268 {
269  // we have a packet. Decode it
270  float **pcm;
271  int samples;
272 
273  // test for success!
274  if (vorbis_synthesis(&m_vb, &m_op) == 0)
275  vorbis_synthesis_blockin(&m_vd, &m_vb);
276 
277  // **pcm is a multichannel float vector. In stereo, for example,
278  // pcm[0] is left, and pcm[1] is right. samples is the size of
279  // each channel. Convert the float values (-1.<=range<=1.) to
280  // whatever PCM format and write it out
281  while ((samples = vorbis_synthesis_pcmout(&m_vd, &pcm)) > 0)
282  {
283  int bout = decodeFrame(pcm, samples, dst);
284 
285  // tell libvorbis how many samples we
286  // actually consumed
287  vorbis_synthesis_read(&m_vd, bout);
288  }
289 
290  m_samples_written = dst.last();
291  return 0;
292 }
293 
294 //***************************************************************************
296 {
297  // ogg_page and ogg_packet structs always point to storage in
298  // libvorbis. They're never freed or manipulated directly
299 
300  vorbis_block_clear(&m_vb);
301  vorbis_dsp_clear(&m_vd);
302  vorbis_comment_clear(&m_vc);
303  vorbis_info_clear(&m_vi); // must be called last
304 }
305 
306 //***************************************************************************
308 {
311  {
312  qWarning("file contains neither nominal bitrate (ABR mode) "
313  "nor quality (VBR mode)");
314 
315  int bitrate = DEFAULT_BITRATE;
316 
317  if (Kwave::toInt(info.rate()) && m_samples_written) {
318  // guess bitrates from the stream
319  const qint64 stream_end_pos = m_source->pos();
320  const qint64 stream_read = stream_end_pos -
321  m_stream_start_pos + 1;
322  double bits = static_cast<double>(stream_read) * 8.0;
323  double seconds = static_cast<double>(m_samples_written) /
324  static_cast<double>(info.rate());
325  bitrate = Kwave::toUint(bits / seconds);
326 
327  // round to nearest standard bitrate
328  bitrate = Kwave::StandardBitrates::instance().nearest(bitrate);
329  qDebug("-> using guessed bitrate %d bits/sec", bitrate);
330  } else {
331  // guessing not possible -> use default
332  qDebug("-> using default %d kBits/sec", bitrate);
333  }
334 
335  info.set(Kwave::INF_BITRATE_NOMINAL, QVariant(bitrate));
336  }
337 }
338 
339 //***************************************************************************
340 //***************************************************************************
bool contains(const FileProperty property) const
Definition: FileInfo.cpp:354
virtual unsigned int tracks() const Q_DECL_OVERRIDE
virtual int decode(Kwave::MultiWriter &dst) Q_DECL_OVERRIDE
double rate() const
Definition: FileInfo.cpp:415
#define DEFAULT_BITRATE
QVariant get(FileProperty key) const
Definition: FileInfo.cpp:372
ogg_stream_state & m_os
#define SAMPLE_MIN
Definition: Sample.h:49
quint64 sample_index_t
Definition: Sample.h:28
VorbisDecoder(QIODevice *source, ogg_sync_state &oy, ogg_stream_state &os, ogg_page &og, ogg_packet &op)
ogg_sync_state & m_oy
virtual void close(Kwave::FileInfo &info) Q_DECL_OVERRIDE
void set(FileProperty key, const QVariant &value)
Definition: FileInfo.cpp:363
virtual sample_index_t last() const
Definition: MultiWriter.cpp:85
void setRate(double rate)
Definition: FileInfo.cpp:424
QIODevice * m_source
Definition: VorbisDecoder.h:96
static int error(QWidget *widget, QString message, QString caption=QString())
Definition: MessageBox.cpp:126
void parseTag(Kwave::FileInfo &info, const char *tag, Kwave::FileProperty property)
int toInt(T x)
Definition: Utils.h:127
void setTracks(unsigned int tracks)
Definition: FileInfo.cpp:454
virtual int nearest(int rate) const
vorbis_dsp_state m_vd
static sample_t double2sample(const double f)
Definition: Sample.h:81
#define _(m)
Definition: memcpy.c:66
#define SAMPLE_MAX
Definition: Sample.h:52
unsigned int toUint(T x)
Definition: Utils.h:109
sample_index_t m_samples_written
virtual void reset() Q_DECL_OVERRIDE
virtual int open(QWidget *widget, Kwave::FileInfo &info) Q_DECL_OVERRIDE
static const StandardBitrates & instance()
FileProperty
Definition: FileInfo.h:45
vorbis_comment m_vc
static int decodeFrame(float **pcm, unsigned int size, Kwave::MultiWriter &dest)
qint32 sample_t
Definition: Sample.h:37