kwave  18.07.70
Kwave::VorbisDecoder Class Reference

#include <VorbisDecoder.h>

Inheritance diagram for Kwave::VorbisDecoder:
Inheritance graph
Collaboration diagram for Kwave::VorbisDecoder:
Collaboration graph

Public Member Functions

 VorbisDecoder (QIODevice *source, ogg_sync_state &oy, ogg_stream_state &os, ogg_page &og, ogg_packet &op)
 
virtual ~VorbisDecoder () Q_DECL_OVERRIDE
 
virtual int open (QWidget *widget, Kwave::FileInfo &info) Q_DECL_OVERRIDE
 
virtual int decode (Kwave::MultiWriter &dst) Q_DECL_OVERRIDE
 
virtual void reset () Q_DECL_OVERRIDE
 
virtual void close (Kwave::FileInfo &info) Q_DECL_OVERRIDE
 
- Public Member Functions inherited from Kwave::OggSubDecoder
virtual ~OggSubDecoder ()
 

Protected Member Functions

void parseTag (Kwave::FileInfo &info, const char *tag, Kwave::FileProperty property)
 

Private Attributes

QIODevice * m_source
 
qint64 m_stream_start_pos
 
sample_index_t m_samples_written
 
ogg_sync_state & m_oy
 
ogg_stream_state & m_os
 
ogg_page & m_og
 
ogg_packet & m_op
 
vorbis_info m_vi
 
vorbis_comment m_vc
 
vorbis_dsp_state m_vd
 
vorbis_block m_vb
 

Detailed Description

Definition at line 36 of file VorbisDecoder.h.

Constructor & Destructor Documentation

◆ VorbisDecoder()

Kwave::VorbisDecoder::VorbisDecoder ( QIODevice *  source,
ogg_sync_state &  oy,
ogg_stream_state &  os,
ogg_page &  og,
ogg_packet &  op 
)
explicit

Constructor

Parameters
sourcepointer to a QIODevice to read from, must not be null
oysync and verify incoming physical bitstream
ostake physical pages, weld into a logical stream of packets
ogone Ogg bitstream page, Vorbis packets are inside
opone raw packet of data for decode

Definition at line 45 of file VorbisDecoder.cpp.

51  m_oy(oy), m_os(os), m_og(og), m_op(op)
52 {
53 }
ogg_stream_state & m_os
ogg_sync_state & m_oy
QIODevice * m_source
Definition: VorbisDecoder.h:96
sample_index_t m_samples_written

◆ ~VorbisDecoder()

virtual Kwave::VorbisDecoder::~VorbisDecoder ( )
inlinevirtual

destructor

Definition at line 55 of file VorbisDecoder.h.

References close(), decode(), open(), parseTag(), and reset().

55 {}
Here is the call graph for this function:

Member Function Documentation

◆ close()

void Kwave::VorbisDecoder::close ( Kwave::FileInfo info)
virtual

finish the decoding, last chance to fix up some file info

Parameters
inforeference to a FileInfo to fill

Implements Kwave::OggSubDecoder.

Definition at line 307 of file VorbisDecoder.cpp.

References Kwave::FileInfo::contains(), DEFAULT_BITRATE, Kwave::INF_BITRATE_NOMINAL, Kwave::INF_VBR_QUALITY, Kwave::StandardBitrates::instance(), m_samples_written, m_source, m_stream_start_pos, Kwave::StandardBitrates::nearest(), Kwave::FileInfo::rate(), Kwave::FileInfo::set(), Kwave::toInt(), and Kwave::toUint().

Referenced by ~VorbisDecoder().

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 }
bool contains(const FileProperty property) const
Definition: FileInfo.cpp:354
double rate() const
Definition: FileInfo.cpp:415
#define DEFAULT_BITRATE
void set(FileProperty key, const QVariant &value)
Definition: FileInfo.cpp:363
QIODevice * m_source
Definition: VorbisDecoder.h:96
int toInt(T x)
Definition: Utils.h:127
virtual int nearest(int rate) const
unsigned int toUint(T x)
Definition: Utils.h:109
sample_index_t m_samples_written
static const StandardBitrates & instance()
Here is the call graph for this function:
Here is the caller graph for this function:

◆ decode()

int Kwave::VorbisDecoder::decode ( Kwave::MultiWriter dst)
virtual

decode received ogg data

Parameters
dsta MultiWriter to be used as sink
Returns
-1 if failed or >= 0 if succeeded

Implements Kwave::OggSubDecoder.

Definition at line 267 of file VorbisDecoder.cpp.

References decodeFrame(), Kwave::MultiWriter::last(), m_op, m_samples_written, m_vb, and m_vd.

Referenced by ~VorbisDecoder().

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 }
virtual sample_index_t last() const
Definition: MultiWriter.cpp:85
vorbis_dsp_state m_vd
sample_index_t m_samples_written
static int decodeFrame(float **pcm, unsigned int size, Kwave::MultiWriter &dest)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ open()

int Kwave::VorbisDecoder::open ( QWidget *  widget,
Kwave::FileInfo info 
)
virtual

parse the header of the stream and initialize the decoder

Parameters
widgeta QWidget to be used as parent for error messages
inforeference to a FileInfo to fill
Returns
-1 if failed or +1 if succeeded

convert the date property to a QDate

Implements Kwave::OggSubDecoder.

Definition at line 73 of file VorbisDecoder.cpp.

References _, Kwave::FileInfo::contains(), DEFAULT_BITRATE, Kwave::MessageBox::error(), Kwave::FileInfo::get(), Kwave::INF_ALBUM, Kwave::INF_AUTHOR, Kwave::INF_BITRATE_LOWER, Kwave::INF_BITRATE_NOMINAL, Kwave::INF_BITRATE_UPPER, Kwave::INF_COMPRESSION, Kwave::INF_CONTACT, Kwave::INF_COPYRIGHT, Kwave::INF_CREATION_DATE, Kwave::INF_ESTIMATED_LENGTH, Kwave::INF_GENRE, Kwave::INF_ISRC, Kwave::INF_LICENSE, Kwave::INF_NAME, Kwave::INF_ORGANIZATION, Kwave::INF_PERFORMER, Kwave::INF_SOFTWARE, Kwave::INF_SOURCE, Kwave::INF_SUBJECT, Kwave::INF_TRACK, Kwave::INF_VBR_QUALITY, Kwave::INF_VERSION, m_og, m_op, m_os, m_oy, m_source, m_stream_start_pos, m_vb, m_vc, m_vd, m_vi, Kwave::Compression::OGG_VORBIS, parseTag(), Kwave::FileInfo::set(), Kwave::FileInfo::setRate(), Kwave::FileInfo::setTracks(), and Kwave::toInt().

Referenced by ~VorbisDecoder().

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 }
bool contains(const FileProperty property) const
Definition: FileInfo.cpp:354
#define DEFAULT_BITRATE
QVariant get(FileProperty key) const
Definition: FileInfo.cpp:372
ogg_stream_state & m_os
quint64 sample_index_t
Definition: Sample.h:28
ogg_sync_state & m_oy
void set(FileProperty key, const QVariant &value)
Definition: FileInfo.cpp:363
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
vorbis_dsp_state m_vd
#define _(m)
Definition: memcpy.c:66
vorbis_comment m_vc
Here is the call graph for this function:
Here is the caller graph for this function:

◆ parseTag()

void Kwave::VorbisDecoder::parseTag ( Kwave::FileInfo info,
const char *  tag,
Kwave::FileProperty  property 
)
protected

Searches for a vorbis comment and renders it into Kwave's FileInfo. If more than one occurrence is found, they are concatenated as a semicolon separated list.

Parameters
infothe file info object to add the tag value
tagname of the field to search for
propertyspecifies the FileProperty for storing the result

Definition at line 57 of file VorbisDecoder.cpp.

References _, m_vc, and Kwave::FileInfo::set().

Referenced by open(), and ~VorbisDecoder().

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 }
void set(FileProperty key, const QVariant &value)
Definition: FileInfo.cpp:363
#define _(m)
Definition: memcpy.c:66
vorbis_comment m_vc
Here is the call graph for this function:
Here is the caller graph for this function:

◆ reset()

void Kwave::VorbisDecoder::reset ( )
virtual

reset the stream info

Implements Kwave::OggSubDecoder.

Definition at line 295 of file VorbisDecoder.cpp.

References m_vb, m_vc, m_vd, and m_vi.

Referenced by ~VorbisDecoder().

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 }
vorbis_dsp_state m_vd
vorbis_comment m_vc
Here is the caller graph for this function:

Member Data Documentation

◆ m_og

ogg_page& Kwave::VorbisDecoder::m_og
private

one Ogg bitstream page. Vorbis packets are inside

Definition at line 111 of file VorbisDecoder.h.

Referenced by open().

◆ m_op

ogg_packet& Kwave::VorbisDecoder::m_op
private

one raw packet of data for decode

Definition at line 114 of file VorbisDecoder.h.

Referenced by decode(), and open().

◆ m_os

ogg_stream_state& Kwave::VorbisDecoder::m_os
private

take physical pages, weld into a logical stream of packets

Definition at line 108 of file VorbisDecoder.h.

Referenced by open().

◆ m_oy

ogg_sync_state& Kwave::VorbisDecoder::m_oy
private

sync and verify incoming physical bitstream

Definition at line 105 of file VorbisDecoder.h.

Referenced by open().

◆ m_samples_written

sample_index_t Kwave::VorbisDecoder::m_samples_written
private

last known position in the output stream [samples]

Definition at line 102 of file VorbisDecoder.h.

Referenced by close(), and decode().

◆ m_source

QIODevice* Kwave::VorbisDecoder::m_source
private

IO device to read from

Definition at line 96 of file VorbisDecoder.h.

Referenced by close(), and open().

◆ m_stream_start_pos

qint64 Kwave::VorbisDecoder::m_stream_start_pos
private

first stream with audio data

Definition at line 99 of file VorbisDecoder.h.

Referenced by close(), and open().

◆ m_vb

vorbis_block Kwave::VorbisDecoder::m_vb
private

local working space for packet->PCM decode

Definition at line 126 of file VorbisDecoder.h.

Referenced by decode(), open(), and reset().

◆ m_vc

vorbis_comment Kwave::VorbisDecoder::m_vc
private

struct that stores all the bitstream user comments

Definition at line 120 of file VorbisDecoder.h.

Referenced by open(), parseTag(), and reset().

◆ m_vd

vorbis_dsp_state Kwave::VorbisDecoder::m_vd
private

central working state for the packet->PCM decoder

Definition at line 123 of file VorbisDecoder.h.

Referenced by decode(), open(), and reset().

◆ m_vi

vorbis_info Kwave::VorbisDecoder::m_vi
private

struct that stores all the static vorbis bitstream settings

Definition at line 117 of file VorbisDecoder.h.

Referenced by open(), and reset().


The documentation for this class was generated from the following files: