bool QWaveDecoder::findChunk(const char *chunkId)
{
    chunk descriptor;

    do {
        if (!peekChunk(&descriptor))
            return false;

        if (qstrncmp(descriptor.id, chunkId, 4) == 0)
            return true;

        // It's possible that bytes->available() is less than the chunk size
        // if it's corrupt.
        junkToSkip = qint64(sizeof(chunk) + descriptor.size);

        // Skip the current amount
        if (junkToSkip > 0)
            discardBytes(junkToSkip);

        // If we still have stuff left, just exit and try again later
        // since we can't call peekChunk
        if (junkToSkip > 0)
            return false;

    } while (source->bytesAvailable() > 0);

    return false;
}
Example #2
0
bool QWaveDecoder::findChunk(const char *chunkId)
{
    if (source->bytesAvailable() < qint64(sizeof(chunk)))
        return false;

    chunk descriptor;
    source->peek(reinterpret_cast<char *>(&descriptor), sizeof(chunk));

    if (qstrncmp(descriptor.id, chunkId, 4) == 0)
        return true;

    while (source->bytesAvailable() >= qint64(sizeof(chunk) + descriptor.size)) {
        discardBytes(sizeof(chunk) + descriptor.size);

        source->peek(reinterpret_cast<char *>(&descriptor), sizeof(chunk));

        if (qstrncmp(descriptor.id, chunkId, 4) == 0)
            return true;
    }

    return false;
}
void QWaveDecoder::handleData()
{
    // As a special "state", if we have junk to skip, we do
    if (junkToSkip > 0) {
        discardBytes(junkToSkip); // this also updates junkToSkip

        // If we couldn't skip all the junk, return
        if (junkToSkip > 0) {
            // We might have run out
            if (source->atEnd())
                parsingFailed();
            return;
        }
    }

    if (state == QWaveDecoder::InitialState) {
        if (source->bytesAvailable() < qint64(sizeof(RIFFHeader)))
            return;

        RIFFHeader riff;
        source->read(reinterpret_cast<char *>(&riff), sizeof(RIFFHeader));

        // RIFF = little endian RIFF, RIFX = big endian RIFF
        if (((qstrncmp(riff.descriptor.id, "RIFF", 4) != 0) && (qstrncmp(riff.descriptor.id, "RIFX", 4) != 0))
                || qstrncmp(riff.type, "WAVE", 4) != 0) {
            parsingFailed();
            return;
        } else {
            state = QWaveDecoder::WaitingForFormatState;
            if (qstrncmp(riff.descriptor.id, "RIFX", 4) == 0)
                bigEndian = true;
            else
                bigEndian = false;
        }
    }

    if (state == QWaveDecoder::WaitingForFormatState) {
        if (findChunk("fmt ")) {
            chunk descriptor;
            peekChunk(&descriptor);

            quint32 rawChunkSize = descriptor.size + sizeof(chunk);
            if (source->bytesAvailable() < qint64(rawChunkSize))
                return;

            WAVEHeader wave;
            source->read(reinterpret_cast<char *>(&wave), sizeof(WAVEHeader));

            if (rawChunkSize > sizeof(WAVEHeader))
                discardBytes(rawChunkSize - sizeof(WAVEHeader));

            // Swizzle this
            if (bigEndian) {
                wave.audioFormat = qFromBigEndian<quint16>(wave.audioFormat);
            } else {
                wave.audioFormat = qFromLittleEndian<quint16>(wave.audioFormat);
            }

            if (wave.audioFormat != 0 && wave.audioFormat != 1) {
                // 32bit wave files have format == 0xFFFE (WAVE_FORMAT_EXTENSIBLE).
                // but don't support them at the moment.
                parsingFailed();
                return;
            } else {
                format.setCodec(QLatin1String("audio/pcm"));

                if (bigEndian) {
                    int bps = qFromBigEndian<quint16>(wave.bitsPerSample);

                    format.setSampleType(bps == 8 ? QAudioFormat::UnSignedInt : QAudioFormat::SignedInt);
                    format.setByteOrder(QAudioFormat::BigEndian);
                    format.setSampleRate(qFromBigEndian<quint32>(wave.sampleRate));
                    format.setSampleSize(bps);
                    format.setChannelCount(qFromBigEndian<quint16>(wave.numChannels));
                } else {
                    int bps = qFromLittleEndian<quint16>(wave.bitsPerSample);

                    format.setSampleType(bps == 8 ? QAudioFormat::UnSignedInt : QAudioFormat::SignedInt);
                    format.setByteOrder(QAudioFormat::LittleEndian);
                    format.setSampleRate(qFromLittleEndian<quint32>(wave.sampleRate));
                    format.setSampleSize(bps);
                    format.setChannelCount(qFromLittleEndian<quint16>(wave.numChannels));
                }

                state = QWaveDecoder::WaitingForDataState;
            }
        }
    }

    if (state == QWaveDecoder::WaitingForDataState) {
        if (findChunk("data")) {
            source->disconnect(SIGNAL(readyRead()), this, SLOT(handleData()));

            chunk descriptor;
            source->read(reinterpret_cast<char *>(&descriptor), sizeof(chunk));
            if (bigEndian)
                descriptor.size = qFromBigEndian<quint32>(descriptor.size);
            else
                descriptor.size = qFromLittleEndian<quint32>(descriptor.size);

            dataSize = descriptor.size;

            haveFormat = true;
            connect(source, SIGNAL(readyRead()), SIGNAL(readyRead()));
            emit formatKnown();

            return;
        }
    }

    // If we hit the end without finding data, it's a parsing error
    if (source->atEnd()) {
        parsingFailed();
    }
}
Example #4
0
void QWaveDecoder::handleData()
{
    if (state == QWaveDecoder::InitialState) {
        if (source->bytesAvailable() < qint64(sizeof(RIFFHeader)))
            return;

        RIFFHeader riff;
        source->read(reinterpret_cast<char *>(&riff), sizeof(RIFFHeader));

        if (qstrncmp(riff.descriptor.id, "RIFF", 4) != 0 ||
            qstrncmp(riff.type, "WAVE", 4) != 0) {
            source->disconnect(SIGNAL(readyRead()), this, SLOT(handleData()));
            emit invalidFormat();

            return;
        } else {
            state = QWaveDecoder::WaitingForFormatState;
        }
    }

    if (state == QWaveDecoder::WaitingForFormatState) {
        if (findChunk("fmt ")) {
            chunk descriptor;
            source->peek(reinterpret_cast<char *>(&descriptor), sizeof(chunk));

            if (source->bytesAvailable() < qint64(descriptor.size + sizeof(chunk)))
                return;

            WAVEHeader wave;
            source->read(reinterpret_cast<char *>(&wave), sizeof(WAVEHeader));
            if (descriptor.size > sizeof(WAVEHeader))
                discardBytes(descriptor.size - sizeof(WAVEHeader));

            if (wave.audioFormat != 0 && wave.audioFormat != 1) {
                source->disconnect(SIGNAL(readyRead()), this, SLOT(handleData()));
                emit invalidFormat();

                return;
            } else {
                int bps = qFromLittleEndian<quint16>(wave.bitsPerSample);

                format.setCodec(QLatin1String("audio/pcm"));
                format.setSampleType(bps == 8 ? QAudioFormat::UnSignedInt : QAudioFormat::SignedInt);
                format.setByteOrder(QAudioFormat::LittleEndian);
                format.setFrequency(qFromLittleEndian<quint32>(wave.sampleRate));
                format.setSampleSize(bps);
                format.setChannels(qFromLittleEndian<quint16>(wave.numChannels));

                state = QWaveDecoder::WaitingForDataState;
            }
        }
    }

    if (state == QWaveDecoder::WaitingForDataState) {
        if (findChunk("data")) {
            source->disconnect(SIGNAL(readyRead()), this, SLOT(handleData()));

            chunk descriptor;
            source->read(reinterpret_cast<char *>(&descriptor), sizeof(chunk));
            dataSize = descriptor.size;

            haveFormat = true;
            connect(source, SIGNAL(readyRead()), SIGNAL(readyRead()));
            emit formatKnown();

            return;
        }
    }

    if (source->atEnd()) {
        source->disconnect(SIGNAL(readyRead()), this, SLOT(handleData()));
        emit invalidFormat();

        return;
    }

}