1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qwavedecoder_p.h"
41
42#include <QtCore/qtimer.h>
43#include <QtCore/qendian.h>
44
45QT_BEGIN_NAMESPACE
46
47QWaveDecoder::QWaveDecoder(QIODevice *s, QObject *parent):
48 QIODevice(parent),
49 haveFormat(false),
50 dataSize(0),
51 source(s),
52 state(QWaveDecoder::InitialState),
53 junkToSkip(0),
54 bigEndian(false)
55{
56 open(mode: QIODevice::ReadOnly | QIODevice::Unbuffered);
57
58 if (enoughDataAvailable())
59 QTimer::singleShot(msec: 0, receiver: this, SLOT(handleData()));
60 else
61 connect(asender: source, SIGNAL(readyRead()), SLOT(handleData()));
62}
63
64QWaveDecoder::~QWaveDecoder()
65{
66}
67
68QAudioFormat QWaveDecoder::audioFormat() const
69{
70 return format;
71}
72
73int QWaveDecoder::duration() const
74{
75 return size() * 1000 / (format.sampleSize() / 8) / format.channelCount() / format.sampleRate();
76}
77
78qint64 QWaveDecoder::size() const
79{
80 return haveFormat ? dataSize : 0;
81}
82
83bool QWaveDecoder::isSequential() const
84{
85 return source->isSequential();
86}
87
88qint64 QWaveDecoder::bytesAvailable() const
89{
90 return haveFormat ? source->bytesAvailable() : 0;
91}
92
93qint64 QWaveDecoder::readData(char *data, qint64 maxlen)
94{
95 return haveFormat ? source->read(data, maxlen) : 0;
96}
97
98qint64 QWaveDecoder::writeData(const char *data, qint64 len)
99{
100 Q_UNUSED(data);
101 Q_UNUSED(len);
102
103 return -1;
104}
105
106void QWaveDecoder::parsingFailed()
107{
108 Q_ASSERT(source);
109 source->disconnect(SIGNAL(readyRead()), receiver: this, SLOT(handleData()));
110 emit parsingError();
111}
112
113void QWaveDecoder::handleData()
114{
115 // As a special "state", if we have junk to skip, we do
116 if (junkToSkip > 0) {
117 discardBytes(numBytes: junkToSkip); // this also updates junkToSkip
118
119 // If we couldn't skip all the junk, return
120 if (junkToSkip > 0) {
121 // We might have run out
122 if (source->atEnd())
123 parsingFailed();
124 return;
125 }
126 }
127
128 if (state == QWaveDecoder::InitialState) {
129 if (source->bytesAvailable() < qint64(sizeof(RIFFHeader)))
130 return;
131
132 RIFFHeader riff;
133 source->read(data: reinterpret_cast<char *>(&riff), maxlen: sizeof(RIFFHeader));
134
135 // RIFF = little endian RIFF, RIFX = big endian RIFF
136 if (((qstrncmp(str1: riff.descriptor.id, str2: "RIFF", len: 4) != 0) && (qstrncmp(str1: riff.descriptor.id, str2: "RIFX", len: 4) != 0))
137 || qstrncmp(str1: riff.type, str2: "WAVE", len: 4) != 0) {
138 parsingFailed();
139 return;
140 } else {
141 state = QWaveDecoder::WaitingForFormatState;
142 if (qstrncmp(str1: riff.descriptor.id, str2: "RIFX", len: 4) == 0)
143 bigEndian = true;
144 else
145 bigEndian = false;
146 }
147 }
148
149 if (state == QWaveDecoder::WaitingForFormatState) {
150 if (findChunk(chunkId: "fmt ")) {
151 chunk descriptor;
152 peekChunk(pChunk: &descriptor);
153
154 quint32 rawChunkSize = descriptor.size + sizeof(chunk);
155 if (source->bytesAvailable() < qint64(rawChunkSize))
156 return;
157
158 WAVEHeader wave;
159 source->read(data: reinterpret_cast<char *>(&wave), maxlen: sizeof(WAVEHeader));
160
161 if (rawChunkSize > sizeof(WAVEHeader))
162 discardBytes(numBytes: rawChunkSize - sizeof(WAVEHeader));
163
164 // Swizzle this
165 if (bigEndian) {
166 wave.audioFormat = qFromBigEndian<quint16>(source: wave.audioFormat);
167 } else {
168 wave.audioFormat = qFromLittleEndian<quint16>(source: wave.audioFormat);
169 }
170
171 if (wave.audioFormat != 0 && wave.audioFormat != 1) {
172 // 32bit wave files have format == 0xFFFE (WAVE_FORMAT_EXTENSIBLE).
173 // but don't support them at the moment.
174 parsingFailed();
175 return;
176 } else {
177 format.setCodec(QLatin1String("audio/pcm"));
178
179 if (bigEndian) {
180 int bps = qFromBigEndian<quint16>(source: wave.bitsPerSample);
181
182 format.setSampleType(bps == 8 ? QAudioFormat::UnSignedInt : QAudioFormat::SignedInt);
183 format.setByteOrder(QAudioFormat::BigEndian);
184 format.setSampleRate(qFromBigEndian<quint32>(source: wave.sampleRate));
185 format.setSampleSize(bps);
186 format.setChannelCount(qFromBigEndian<quint16>(source: wave.numChannels));
187 } else {
188 int bps = qFromLittleEndian<quint16>(source: wave.bitsPerSample);
189
190 format.setSampleType(bps == 8 ? QAudioFormat::UnSignedInt : QAudioFormat::SignedInt);
191 format.setByteOrder(QAudioFormat::LittleEndian);
192 format.setSampleRate(qFromLittleEndian<quint32>(source: wave.sampleRate));
193 format.setSampleSize(bps);
194 format.setChannelCount(qFromLittleEndian<quint16>(source: wave.numChannels));
195 }
196
197 state = QWaveDecoder::WaitingForDataState;
198 }
199 }
200 }
201
202 if (state == QWaveDecoder::WaitingForDataState) {
203 if (findChunk(chunkId: "data")) {
204 source->disconnect(SIGNAL(readyRead()), receiver: this, SLOT(handleData()));
205
206 chunk descriptor;
207 source->read(data: reinterpret_cast<char *>(&descriptor), maxlen: sizeof(chunk));
208 if (bigEndian)
209 descriptor.size = qFromBigEndian<quint32>(source: descriptor.size);
210 else
211 descriptor.size = qFromLittleEndian<quint32>(source: descriptor.size);
212
213 dataSize = descriptor.size;
214
215 haveFormat = true;
216 connect(asender: source, SIGNAL(readyRead()), SIGNAL(readyRead()));
217 emit formatKnown();
218
219 return;
220 }
221 }
222
223 // If we hit the end without finding data, it's a parsing error
224 if (source->atEnd()) {
225 parsingFailed();
226 }
227}
228
229bool QWaveDecoder::enoughDataAvailable()
230{
231 chunk descriptor;
232 if (!peekChunk(pChunk: &descriptor, handleEndianness: false))
233 return false;
234
235 // This is only called for the RIFF/RIFX header, before bigEndian is set,
236 // so we have to manually swizzle
237 if (qstrncmp(str1: descriptor.id, str2: "RIFX", len: 4) == 0)
238 descriptor.size = qFromBigEndian<quint32>(source: descriptor.size);
239 if (qstrncmp(str1: descriptor.id, str2: "RIFF", len: 4) == 0)
240 descriptor.size = qFromLittleEndian<quint32>(source: descriptor.size);
241
242 if (source->bytesAvailable() < qint64(sizeof(chunk) + descriptor.size))
243 return false;
244
245 return true;
246}
247
248bool QWaveDecoder::findChunk(const char *chunkId)
249{
250 chunk descriptor;
251
252 do {
253 if (!peekChunk(pChunk: &descriptor))
254 return false;
255
256 if (qstrncmp(str1: descriptor.id, str2: chunkId, len: 4) == 0)
257 return true;
258
259 // It's possible that bytes->available() is less than the chunk size
260 // if it's corrupt.
261 junkToSkip = qint64(sizeof(chunk) + descriptor.size);
262
263 // Skip the current amount
264 if (junkToSkip > 0)
265 discardBytes(numBytes: junkToSkip);
266
267 // If we still have stuff left, just exit and try again later
268 // since we can't call peekChunk
269 if (junkToSkip > 0)
270 return false;
271
272 } while (source->bytesAvailable() > 0);
273
274 return false;
275}
276
277bool QWaveDecoder::peekChunk(chunk *pChunk, bool handleEndianness)
278{
279 if (source->bytesAvailable() < qint64(sizeof(chunk)))
280 return false;
281
282 source->peek(data: reinterpret_cast<char *>(pChunk), maxlen: sizeof(chunk));
283 if (handleEndianness) {
284 if (bigEndian)
285 pChunk->size = qFromBigEndian<quint32>(source: pChunk->size);
286 else
287 pChunk->size = qFromLittleEndian<quint32>(source: pChunk->size);
288 }
289 return true;
290}
291
292void QWaveDecoder::discardBytes(qint64 numBytes)
293{
294 // Discards a number of bytes
295 // If the iodevice doesn't have this many bytes in it,
296 // remember how much more junk we have to skip.
297 if (source->isSequential()) {
298 QByteArray r = source->read(maxlen: qMin(a: numBytes, b: qint64(16384))); // uggh, wasted memory, limit to a max of 16k
299 if (r.size() < numBytes)
300 junkToSkip = numBytes - r.size();
301 else
302 junkToSkip = 0;
303 } else {
304 quint64 origPos = source->pos();
305 source->seek(pos: source->pos() + numBytes);
306 junkToSkip = origPos + numBytes - source->pos();
307 }
308}
309
310QT_END_NAMESPACE
311
312#include "moc_qwavedecoder_p.cpp"
313

source code of qtmultimedia/src/multimedia/audio/qwavedecoder_p.cpp