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