kwave  18.07.70
FlacDecoder.cpp
Go to the documentation of this file.
1 /*************************************************************************
2  FlacDecoder.cpp - decoder for FLAC data
3  -------------------
4  begin : Tue Feb 28 2004
5  copyright : (C) 2004 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 <QDateTime>
21 
22 #include <KLocalizedString>
23 
24 #include "libkwave/Compression.h"
25 #include "libkwave/MessageBox.h"
26 #include "libkwave/MultiWriter.h"
27 #include "libkwave/Sample.h"
28 #include "libkwave/String.h"
29 #include "libkwave/Writer.h"
30 
31 #include "FlacCodecPlugin.h"
32 #include "FlacDecoder.h"
33 
34 //***************************************************************************
36  :Kwave::Decoder(),
37  FLAC::Decoder::Stream(),
38  m_source(Q_NULLPTR),
39  m_dest(Q_NULLPTR),
40  m_vorbis_comment_map()
41 {
44 }
45 
46 //***************************************************************************
48 {
49  if (m_source) close();
50 }
51 
52 //***************************************************************************
54 {
55  return new Kwave::FlacDecoder();
56 }
57 
58 //***************************************************************************
59 ::FLAC__StreamDecoderReadStatus Kwave::FlacDecoder::read_callback(
60  FLAC__byte buffer[], size_t *bytes)
61 {
62  Q_ASSERT(bytes);
63  Q_ASSERT(m_source);
64  if (!bytes || !m_source) return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
65 
66  // check for EOF
67  if (m_source->atEnd()) {
68  *bytes = 0;
69  return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
70  }
71 
72  // read into application buffer
73  *bytes = static_cast<unsigned>(m_source->read(
74  reinterpret_cast<char *>(&(buffer[0])),
75  static_cast<qint64>(*bytes)
76  ));
77 
78  if (!*bytes) return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
79 
80  return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
81 }
82 
83 //***************************************************************************
84 ::FLAC__StreamDecoderWriteStatus Kwave::FlacDecoder::write_callback(
85  const ::FLAC__Frame *frame,
86  const FLAC__int32 * const buffer[])
87 {
88  Q_ASSERT(buffer);
89  Q_ASSERT(frame);
90  Q_ASSERT(m_dest);
91  if (!buffer || !frame || !m_dest)
92  return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
93 
94  const unsigned int samples = frame->header.blocksize;
95 
96  const unsigned int tracks = Kwave::FileInfo(metaData()).tracks();
97  Q_ASSERT(samples);
98  Q_ASSERT(tracks);
99  if (!samples || !tracks)
100  return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
101 
102  Kwave::SampleArray dst(samples);
103 
104  // expand the samples up to the correct number of bits
105  int shift = SAMPLE_BITS - Kwave::FileInfo(metaData()).bits();
106  if (shift < 0) shift = 0;
107  unsigned int mul = (1 << shift);
108 
109  // decode the samples into a temporary buffer and
110  // flush it to the Writer(s), track by track
111  for (unsigned int track=0; track < tracks; track++) {
112  Kwave::Writer *writer = (*m_dest)[track];
113  Q_ASSERT(writer);
114  if (!writer) continue;
115  const FLAC__int32 *src = buffer[track];
116  sample_t *d = dst.data();
117 
118  for (unsigned int sample = 0; sample < samples; sample++) {
119  // the following cast is only necessary if
120  // sample_t is not equal to a quint32
121  sample_t s = static_cast<sample_t>(*src++);
122 
123  // correct precision
124  if (shift) s *= mul;
125 
126  // write to destination buffer
127  *d++ = s;
128  }
129 
130  // flush the temporary buffer
131  (*writer) << dst;
132  }
133 
134  // at this point we check for a user-cancel
135  return (m_dest->isCanceled()) ?
136  FLAC__STREAM_DECODER_WRITE_STATUS_ABORT :
137  FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
138 }
139 
140 //***************************************************************************
142  const FLAC::Metadata::StreamInfo &stream_info)
143 {
144  qDebug("FLAC stream info");
145  qDebug("\tmin_blocksize = %d", stream_info.get_min_blocksize());
146  qDebug("\tmax_blocksize = %d", stream_info.get_max_blocksize());
147  qDebug("\tmin_framesize = %d", stream_info.get_min_framesize());
148  qDebug("\tmax_framesize = %d", stream_info.get_max_framesize());
149 
150  Kwave::FileInfo info(metaData());
151  info.setRate(stream_info.get_sample_rate());
152  info.setTracks(stream_info.get_channels());
153  info.setBits(stream_info.get_bits_per_sample());
154  info.setLength(stream_info.get_total_samples());
156 
157  qDebug("Bitstream is %u channel, %uHz",
158  stream_info.get_channels(),
159  stream_info.get_sample_rate());
160 }
161 
162 //***************************************************************************
164  const FLAC::Metadata::VorbisComment &vorbis_comments)
165 {
166  Kwave::FileInfo info(metaData());
167 
168  // first of all: the vendor string, specifying the software
169  QString vendor = QString::fromUtf8(reinterpret_cast<const char *>(
170  vorbis_comments.get_vendor_string()));
171  if (vendor.length()) {
172  info.set(Kwave::INF_SOFTWARE, vendor);
173  qDebug("Encoded by: '%s'\n\n", DBG(vendor));
174  }
175 
176  // parse all vorbis comments into Kwave file properties
177  for (unsigned int i = 0; i < vorbis_comments.get_num_comments(); i++) {
178  FLAC::Metadata::VorbisComment::Entry comment =
179  vorbis_comments.get_comment(i);
180  Q_ASSERT(comment.is_valid());
181  if (!comment.is_valid()) continue;
182 
183  QString name = QString::fromUtf8(
184  comment.get_field_name(), comment.get_field_name_length());
185  QString value = QString::fromUtf8(
186  comment.get_field_value(), comment.get_field_value_length());
187 
188  if (!m_vorbis_comment_map.contains(name)) continue;
189 
190  // we have a known vorbis tag
192  info.set(prop, value);
193  }
194 
195  // convert the date property to a QDate
197  QString str_date =
198  QVariant(info.get(Kwave::INF_CREATION_DATE)).toString();
199  QDate date;
200  date = QDate::fromString(str_date, Qt::ISODate);
201  if (!date.isValid()) {
202  int year = str_date.toInt();
203  date.setDate(year, 1, 1);
204  }
205  if (date.isValid()) info.set(Kwave::INF_CREATION_DATE, date);
206  }
207 
209 }
210 
211 //***************************************************************************
213  const ::FLAC__StreamMetadata *metadata)
214 {
215  Q_ASSERT(metadata);
216  if (!metadata) return;
217 
218  switch (metadata->type) {
219  case FLAC__METADATA_TYPE_STREAMINFO: {
220  FLAC::Metadata::StreamInfo stream_info(
221  const_cast< ::FLAC__StreamMetadata * >(metadata), true);
222  parseStreamInfo(stream_info);
223  break;
224  }
225  case FLAC__METADATA_TYPE_PADDING:
226  // -> ignored
227  break;
228  case FLAC__METADATA_TYPE_APPLICATION:
229  qDebug("FLAC metadata: application data");
230  break;
231  case FLAC__METADATA_TYPE_SEEKTABLE:
232  qDebug("FLAC metadata: seektable - not supported yet");
233  break;
234  case FLAC__METADATA_TYPE_VORBIS_COMMENT: {
235  FLAC::Metadata::VorbisComment vorbis_comments(
236  const_cast< ::FLAC__StreamMetadata * >(metadata), true);
237  parseVorbisComments(vorbis_comments);
238  break;
239  }
240  case FLAC__METADATA_TYPE_CUESHEET:
241  qDebug("FLAC metadata: cuesheet - not supported yet");
242  break;
243  case FLAC__METADATA_TYPE_UNDEFINED:
244  default:
245  qDebug("FLAC metadata: unknown/undefined type");
246  }
247 }
248 
249 //***************************************************************************
250 void Kwave::FlacDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
251 {
252  qDebug("FlacDecoder::error_callback: status=%d", status);
253 }
254 
255 //***************************************************************************
256 bool Kwave::FlacDecoder::open(QWidget *widget, QIODevice &src)
257 {
258  metaData().clear();
259  Q_ASSERT(!m_source);
260  if (m_source) qWarning("FlacDecoder::open(), already open !");
261 
262  // try to open the source
263  if (!src.open(QIODevice::ReadOnly)) {
264  qWarning("failed to open source !");
265  return false;
266  }
267 
268  // take over the source
269  m_source = &src;
270 
271  /********** Decoder setup ************/
272  qDebug("--- FlacDecoder::open() ---");
273  set_metadata_respond_all();
274 
275  // initialize the stream
276  FLAC__StreamDecoderInitStatus init_state = init();
277  if (init_state > FLAC__STREAM_DECODER_INIT_STATUS_OK) {
278  Kwave::MessageBox::error(widget, i18n(
279  "Opening the FLAC bitstream failed."));
280  return false;
281  }
282 
283  // read in all metadata
284  process_until_end_of_metadata();
285 
286  FLAC::Decoder::Stream::State state = get_state();
287  if (state >= FLAC__STREAM_DECODER_END_OF_STREAM) {
288  Kwave::MessageBox::error(widget, i18n(
289  "Error while parsing the FLAC metadata. (%s)"),
290  _(state.as_cstring()));
291  return false;
292  }
293 
294  // set some more standard properties
295  Kwave::FileInfo info(metaData());
299 
300  return true;
301 }
302 
303 //***************************************************************************
304 bool Kwave::FlacDecoder::decode(QWidget * /* widget */,
305  Kwave::MultiWriter &dst)
306 {
307  Q_ASSERT(m_source);
308  if (!m_source) return false;
309 
310  m_dest = &dst;
311 
312  // read in all remaining data
313  qDebug("FlacDecoder::decode(...)");
314  process_until_end_of_stream();
315 
316  m_dest = Q_NULLPTR;
317  Kwave::FileInfo info(metaData());
318  info.setLength(dst.last() ? (dst.last() + 1) : 0);
320 
321  // return with a valid Signal, even if the user pressed cancel !
322  return true;
323 }
324 
325 //***************************************************************************
327 {
328  finish();
329  m_source = Q_NULLPTR;
330 }
331 
332 //***************************************************************************
333 //***************************************************************************
bool contains(const FileProperty property) const
Definition: FileInfo.cpp:354
virtual void metadata_callback(const ::FLAC__StreamMetadata *metadata) Q_DECL_OVERRIDE
Definition: App.h:33
virtual void error_callback(::FLAC__StreamDecoderErrorStatus status) Q_DECL_OVERRIDE
QVariant get(FileProperty key) const
Definition: FileInfo.cpp:372
QIODevice * m_source
Definition: FlacDecoder.h:138
Kwave::MultiWriter * m_dest
Definition: FlacDecoder.h:141
Kwave::VorbisCommentMap m_vorbis_comment_map
Definition: FlacDecoder.h:144
virtual Kwave::Decoder * instance() Q_DECL_OVERRIDE
Definition: FlacDecoder.cpp:53
virtual ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 *const buffer[]) Q_DECL_OVERRIDE
Definition: FlacDecoder.cpp:84
void set(FileProperty key, const QVariant &value)
Definition: FileInfo.cpp:363
virtual sample_index_t last() const
Definition: MultiWriter.cpp:85
virtual ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes) Q_DECL_OVERRIDE
Definition: FlacDecoder.cpp:59
const char name[16]
Definition: memcpy.c:510
static int error(QWidget *widget, QString message, QString caption=QString())
Definition: MessageBox.cpp:126
#define DEFAULT_MIME_TYPE
void setLength(sample_index_t length)
Definition: FileInfo.cpp:409
virtual bool open(QWidget *widget, QIODevice &source) Q_DECL_OVERRIDE
virtual void replace(const MetaDataList &list)
virtual Kwave::MetaDataList & metaData()
Definition: Decoder.h:78
virtual ~FlacDecoder() Q_DECL_OVERRIDE
Definition: FlacDecoder.cpp:47
#define REGISTER_MIME_TYPES
bool isCanceled() const
Definition: MultiWriter.h:64
unsigned int tracks() const
Definition: FileInfo.cpp:445
virtual bool decode(QWidget *widget, Kwave::MultiWriter &dst) Q_DECL_OVERRIDE
#define REGISTER_COMPRESSION_TYPES
#define _(m)
Definition: memcpy.c:66
#define DBG(qs)
Definition: String.h:55
void parseStreamInfo(const FLAC::Metadata::StreamInfo &stream_info)
unsigned int bits() const
Definition: FileInfo.cpp:430
virtual void close() Q_DECL_OVERRIDE
FileProperty
Definition: FileInfo.h:45
sample_t * data()
Definition: SampleArray.h:62
void parseVorbisComments(const FLAC::Metadata::VorbisComment &vorbis_comments)
#define SAMPLE_BITS
Definition: Sample.h:43
qint32 sample_t
Definition: Sample.h:37