1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qwavedecoder.h"
5
6#include <QtCore/qtimer.h>
7#include <QtCore/qendian.h>
8#include <limits.h>
9#include <qdebug.h>
10
11QT_BEGIN_NAMESPACE
12
13QWaveDecoder::QWaveDecoder(QIODevice *device, QObject *parent)
14 : QIODevice(parent),
15 device(device)
16{
17}
18
19QWaveDecoder::QWaveDecoder(QIODevice *device, const QAudioFormat &format, QObject *parent)
20 : QIODevice(parent),
21 device(device),
22 format(format)
23{
24}
25
26QWaveDecoder::~QWaveDecoder() = default;
27
28bool QWaveDecoder::open(QIODevice::OpenMode mode)
29{
30 bool canOpen = false;
31 if (mode & QIODevice::ReadOnly && mode & ~QIODevice::WriteOnly) {
32 canOpen = QIODevice::open(mode: mode | QIODevice::Unbuffered);
33 if (canOpen && enoughDataAvailable())
34 handleData();
35 else
36 connect(sender: device, signal: &QIODevice::readyRead, context: this, slot: &QWaveDecoder::handleData);
37 return canOpen;
38 }
39
40 if (mode & QIODevice::WriteOnly) {
41 if (format.sampleFormat() != QAudioFormat::Int16)
42 return false; // data format is not supported
43 canOpen = QIODevice::open(mode);
44 if (canOpen && writeHeader())
45 haveHeader = true;
46 return canOpen;
47 }
48 return QIODevice::open(mode);
49}
50
51void QWaveDecoder::close()
52{
53 if (isOpen() && (openMode() & QIODevice::WriteOnly)) {
54 Q_ASSERT(dataSize < INT_MAX);
55 if (!device->isOpen() || !writeDataLength())
56 qWarning() << "Failed to finalize wav file";
57 }
58 QIODevice::close();
59}
60
61bool QWaveDecoder::seek(qint64 pos)
62{
63 return device->seek(pos);
64}
65
66qint64 QWaveDecoder::pos() const
67{
68 return device->pos();
69}
70
71void QWaveDecoder::setIODevice(QIODevice * /* device */)
72{
73}
74
75QAudioFormat QWaveDecoder::audioFormat() const
76{
77 return format;
78}
79
80QIODevice* QWaveDecoder::getDevice()
81{
82 return device;
83}
84
85int QWaveDecoder::duration() const
86{
87 if (openMode() & QIODevice::WriteOnly)
88 return 0;
89 int bytesPerSec = format.bytesPerFrame() * format.sampleRate();
90 return bytesPerSec ? size() * 1000 / bytesPerSec : 0;
91}
92
93qint64 QWaveDecoder::size() const
94{
95 if (openMode() & QIODevice::ReadOnly) {
96 if (!haveFormat)
97 return 0;
98 if (bps == 24)
99 return dataSize*2/3;
100 return dataSize;
101 } else {
102 return device->size();
103 }
104}
105
106bool QWaveDecoder::isSequential() const
107{
108 return device->isSequential();
109}
110
111qint64 QWaveDecoder::bytesAvailable() const
112{
113 return haveFormat ? device->bytesAvailable() : 0;
114}
115
116qint64 QWaveDecoder::headerLength()
117{
118 return HeaderLength;
119}
120
121qint64 QWaveDecoder::readData(char *data, qint64 maxlen)
122{
123 const int bytesPerSample = format.bytesPerSample();
124 if (!haveFormat || bytesPerSample == 0)
125 return 0;
126
127 if (bps == 24) {
128 // 24 bit WAV, read in as 16 bit
129 qint64 l = 0;
130 while (l < maxlen - 1) {
131 char tmp[3];
132 device->read(data: tmp, maxlen: 3);
133 if (byteSwap)
134 qSwap(value1&: tmp[0], value2&: tmp[2]);
135#if Q_BYTE_ORDER == Q_BIG_ENDIAN
136 data[0] = tmp[0];
137 data[1] = tmp[1];
138#else
139 data[0] = tmp[1];
140 data[1] = tmp[2];
141#endif
142 data += 2;
143 l += 2;
144 }
145 return l;
146 }
147
148 qint64 nSamples = maxlen / bytesPerSample;
149 maxlen = nSamples * bytesPerSample;
150 int read = device->read(data, maxlen);
151
152 if (!byteSwap || format.bytesPerFrame() == 1)
153 return read;
154
155 nSamples = read / bytesPerSample;
156 switch (bytesPerSample) {
157 case 2:
158 qbswap<2>(source: data, count: nSamples, dest: data);
159 break;
160 case 4:
161 qbswap<4>(source: data, count: nSamples, dest: data);
162 break;
163 default:
164 Q_UNREACHABLE();
165 }
166 return read;
167
168}
169
170qint64 QWaveDecoder::writeData(const char *data, qint64 len)
171{
172 if (!haveHeader)
173 return 0;
174 qint64 written = device->write(data, len);
175 dataSize += written;
176 return written;
177}
178
179bool QWaveDecoder::writeHeader()
180{
181 if (device->size() != 0)
182 return false;
183
184#ifndef Q_LITTLE_ENDIAN
185 // only implemented for LITTLE ENDIAN
186 return false;
187#endif
188
189 CombinedHeader header;
190
191 memset(s: &header, c: 0, n: HeaderLength);
192
193 // RIFF header
194 memcpy(dest: header.riff.descriptor.id,src: "RIFF",n: 4);
195 qToLittleEndian<quint32>(src: quint32(dataSize + HeaderLength - 8),
196 dest: reinterpret_cast<unsigned char*>(&header.riff.descriptor.size));
197 memcpy(dest: header.riff.type, src: "WAVE",n: 4);
198
199 // WAVE header
200 memcpy(dest: header.wave.descriptor.id,src: "fmt ",n: 4);
201 qToLittleEndian<quint32>(src: quint32(16),
202 dest: reinterpret_cast<unsigned char*>(&header.wave.descriptor.size));
203 qToLittleEndian<quint16>(src: quint16(1),
204 dest: reinterpret_cast<unsigned char*>(&header.wave.audioFormat));
205 qToLittleEndian<quint16>(src: quint16(format.channelCount()),
206 dest: reinterpret_cast<unsigned char*>(&header.wave.numChannels));
207 qToLittleEndian<quint32>(src: quint32(format.sampleRate()),
208 dest: reinterpret_cast<unsigned char*>(&header.wave.sampleRate));
209 qToLittleEndian<quint32>(src: quint32(format.sampleRate() * format.bytesPerFrame()),
210 dest: reinterpret_cast<unsigned char*>(&header.wave.byteRate));
211 qToLittleEndian<quint16>(src: quint16(format.channelCount() * format.bytesPerSample()),
212 dest: reinterpret_cast<unsigned char*>(&header.wave.blockAlign));
213 qToLittleEndian<quint16>(src: quint16(format.bytesPerSample() * 8),
214 dest: reinterpret_cast<unsigned char*>(&header.wave.bitsPerSample));
215
216 // DATA header
217 memcpy(dest: header.data.descriptor.id,src: "data",n: 4);
218 qToLittleEndian<quint32>(src: quint32(dataSize),
219 dest: reinterpret_cast<unsigned char*>(&header.data.descriptor.size));
220
221 return device->write(data: reinterpret_cast<const char *>(&header), len: HeaderLength);
222}
223
224bool QWaveDecoder::writeDataLength()
225{
226#ifndef Q_LITTLE_ENDIAN
227 // only implemented for LITTLE ENDIAN
228 return false;
229#endif
230
231 if (isSequential())
232 return false;
233
234 // seek to RIFF header size, see header.riff.descriptor.size above
235 if (!device->seek(pos: 4)) {
236 qDebug() << "can't seek";
237 return false;
238 }
239
240 quint32 length = dataSize + HeaderLength - 8;
241 if (device->write(data: reinterpret_cast<const char *>(&length), len: 4) != 4)
242 return false;
243
244 // seek to DATA header size, see header.data.descriptor.size above
245 if (!device->seek(pos: 40))
246 return false;
247
248 return device->write(data: reinterpret_cast<const char *>(&dataSize), len: 4);
249}
250
251void QWaveDecoder::parsingFailed()
252{
253 Q_ASSERT(device);
254 disconnect(sender: device, signal: &QIODevice::readyRead, receiver: this, slot: &QWaveDecoder::handleData);
255 emit parsingError();
256}
257
258void QWaveDecoder::handleData()
259{
260 if (openMode() == QIODevice::WriteOnly)
261 return;
262
263 // As a special "state", if we have junk to skip, we do
264 if (junkToSkip > 0) {
265 discardBytes(numBytes: junkToSkip); // this also updates junkToSkip
266
267 // If we couldn't skip all the junk, return
268 if (junkToSkip > 0) {
269 // We might have run out
270 if (device->atEnd())
271 parsingFailed();
272 return;
273 }
274 }
275
276 if (state == QWaveDecoder::InitialState) {
277 if (device->bytesAvailable() < qint64(sizeof(RIFFHeader)))
278 return;
279
280 RIFFHeader riff;
281 device->read(data: reinterpret_cast<char *>(&riff), maxlen: sizeof(RIFFHeader));
282
283 // RIFF = little endian RIFF, RIFX = big endian RIFF
284 if (((qstrncmp(str1: riff.descriptor.id, str2: "RIFF", len: 4) != 0) && (qstrncmp(str1: riff.descriptor.id, str2: "RIFX", len: 4) != 0))
285 || qstrncmp(str1: riff.type, str2: "WAVE", len: 4) != 0) {
286 parsingFailed();
287 return;
288 }
289
290 state = QWaveDecoder::WaitingForFormatState;
291 bigEndian = (qstrncmp(str1: riff.descriptor.id, str2: "RIFX", len: 4) == 0);
292 byteSwap = (bigEndian != (QSysInfo::ByteOrder == QSysInfo::BigEndian));
293 }
294
295 if (state == QWaveDecoder::WaitingForFormatState) {
296 if (findChunk(chunkId: "fmt ")) {
297 chunk descriptor;
298 const bool peekSuccess = peekChunk(pChunk: &descriptor);
299 Q_ASSERT(peekSuccess);
300
301 quint32 rawChunkSize = descriptor.size + sizeof(chunk);
302 if (device->bytesAvailable() < qint64(rawChunkSize))
303 return;
304
305 WAVEHeader wave;
306 device->read(data: reinterpret_cast<char *>(&wave), maxlen: sizeof(WAVEHeader));
307
308 if (rawChunkSize > sizeof(WAVEHeader))
309 discardBytes(numBytes: rawChunkSize - sizeof(WAVEHeader));
310
311 // Swizzle this
312 if (bigEndian) {
313 wave.audioFormat = qFromBigEndian<quint16>(source: wave.audioFormat);
314 } else {
315 wave.audioFormat = qFromLittleEndian<quint16>(source: wave.audioFormat);
316 }
317
318 if (wave.audioFormat != 0 && wave.audioFormat != 1) {
319 // 32bit wave files have format == 0xFFFE (WAVE_FORMAT_EXTENSIBLE).
320 // but don't support them at the moment.
321 parsingFailed();
322 return;
323 }
324
325 int rate;
326 int channels;
327 if (bigEndian) {
328 bps = qFromBigEndian<quint16>(source: wave.bitsPerSample);
329 rate = qFromBigEndian<quint32>(source: wave.sampleRate);
330 channels = qFromBigEndian<quint16>(source: wave.numChannels);
331 } else {
332 bps = qFromLittleEndian<quint16>(source: wave.bitsPerSample);
333 rate = qFromLittleEndian<quint32>(source: wave.sampleRate);
334 channels = qFromLittleEndian<quint16>(source: wave.numChannels);
335 }
336
337 QAudioFormat::SampleFormat fmt = QAudioFormat::Unknown;
338 switch(bps) {
339 case 8:
340 fmt = QAudioFormat::UInt8;
341 break;
342 case 16:
343 fmt = QAudioFormat::Int16;
344 break;
345 case 24:
346 fmt = QAudioFormat::Int16;
347 break;
348 case 32:
349 fmt = QAudioFormat::Int32;
350 break;
351 }
352 if (fmt == QAudioFormat::Unknown || rate == 0 || channels == 0) {
353 parsingFailed();
354 return;
355 }
356
357 format.setSampleFormat(fmt);
358 format.setSampleRate(rate);
359 format.setChannelCount(channels);
360
361 state = QWaveDecoder::WaitingForDataState;
362 }
363 }
364
365 if (state == QWaveDecoder::WaitingForDataState) {
366 if (findChunk(chunkId: "data")) {
367 disconnect(sender: device, signal: &QIODevice::readyRead, receiver: this, slot: &QWaveDecoder::handleData);
368
369 chunk descriptor;
370 device->read(data: reinterpret_cast<char *>(&descriptor), maxlen: sizeof(chunk));
371 if (bigEndian)
372 descriptor.size = qFromBigEndian<quint32>(source: descriptor.size);
373 else
374 descriptor.size = qFromLittleEndian<quint32>(source: descriptor.size);
375
376 dataSize = descriptor.size; //means the data size from the data header, not the actual file size
377 if (!dataSize)
378 dataSize = device->size() - headerLength();
379
380 haveFormat = true;
381 connect(sender: device, signal: &QIODevice::readyRead, context: this, slot: &QIODevice::readyRead);
382 emit formatKnown();
383
384 return;
385 }
386 }
387
388 // If we hit the end without finding data, it's a parsing error
389 if (device->atEnd()) {
390 parsingFailed();
391 }
392}
393
394bool QWaveDecoder::enoughDataAvailable()
395{
396 chunk descriptor;
397 if (!peekChunk(pChunk: &descriptor, handleEndianness: false))
398 return false;
399
400 // This is only called for the RIFF/RIFX header, before bigEndian is set,
401 // so we have to manually swizzle
402 if (qstrncmp(str1: descriptor.id, str2: "RIFX", len: 4) == 0)
403 descriptor.size = qFromBigEndian<quint32>(source: descriptor.size);
404 if (qstrncmp(str1: descriptor.id, str2: "RIFF", len: 4) == 0)
405 descriptor.size = qFromLittleEndian<quint32>(source: descriptor.size);
406
407 if (device->bytesAvailable() < qint64(sizeof(chunk)) + descriptor.size)
408 return false;
409
410 return true;
411}
412
413bool QWaveDecoder::findChunk(const char *chunkId)
414{
415 chunk descriptor;
416
417 do {
418 if (!peekChunk(pChunk: &descriptor))
419 return false;
420
421 if (qstrncmp(str1: descriptor.id, str2: chunkId, len: 4) == 0)
422 return true;
423
424 // A program reading a RIFF file can skip over any chunk whose chunk
425 // ID it doesn't recognize; it simply skips the number of bytes specified
426 // by ckSize plus the pad byte, if present. See Multimedia Programming
427 // Interface and Data Specifications 1.0. IBM / Microsoft. August 1991. pp. 10-11.
428 const quint32 sizeWithPad = descriptor.size + (descriptor.size & 1);
429
430 // It's possible that bytes->available() is less than the chunk size
431 // if it's corrupt.
432 junkToSkip = qint64(sizeof(chunk) + sizeWithPad);
433
434 // Skip the current amount
435 if (junkToSkip > 0)
436 discardBytes(numBytes: junkToSkip);
437
438 // If we still have stuff left, just exit and try again later
439 // since we can't call peekChunk
440 if (junkToSkip > 0)
441 return false;
442
443 } while (device->bytesAvailable() > 0);
444
445 return false;
446}
447
448bool QWaveDecoder::peekChunk(chunk *pChunk, bool handleEndianness)
449{
450 if (device->bytesAvailable() < qint64(sizeof(chunk)))
451 return false;
452
453 if (!device->peek(data: reinterpret_cast<char *>(pChunk), maxlen: sizeof(chunk)))
454 return false;
455
456 if (handleEndianness) {
457 if (bigEndian)
458 pChunk->size = qFromBigEndian<quint32>(source: pChunk->size);
459 else
460 pChunk->size = qFromLittleEndian<quint32>(source: pChunk->size);
461 }
462 return true;
463}
464
465void QWaveDecoder::discardBytes(qint64 numBytes)
466{
467 // Discards a number of bytes
468 // If the iodevice doesn't have this many bytes in it,
469 // remember how much more junk we have to skip.
470 if (device->isSequential()) {
471 QByteArray r = device->read(maxlen: qMin(a: numBytes, b: qint64(16384))); // uggh, wasted memory, limit to a max of 16k
472 if (r.size() < numBytes)
473 junkToSkip = numBytes - r.size();
474 else
475 junkToSkip = 0;
476 } else {
477 quint64 origPos = device->pos();
478 device->seek(pos: device->pos() + numBytes);
479 junkToSkip = origPos + numBytes - device->pos();
480 }
481}
482
483QT_END_NAMESPACE
484
485#include "moc_qwavedecoder.cpp"
486

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

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