void AVIDecoder::readNextPacket() { uint32 nextTag = _fileStream->readUint32BE(); uint32 size = _fileStream->readUint32LE(); if (_fileStream->eos()) return; if (nextTag == ID_LIST) { // A list of audio/video chunks int32 startPos = _fileStream->pos(); if (_fileStream->readUint32BE() != ID_REC) error("Expected 'rec ' LIST"); size -= 4; // subtract list type // Decode chunks in the list while (_fileStream->pos() < startPos + (int32)size) readNextPacket(); return; } else if (nextTag == ID_JUNK || nextTag == ID_IDX1) { skipChunk(size); return; } Track *track = getTrack(getStreamIndex(nextTag)); if (!track) error("Cannot get track from tag '%s'", tag2str(nextTag)); Common::SeekableReadStream *chunk = 0; if (size != 0) { chunk = _fileStream->readStream(size); _fileStream->skip(size & 1); } if (track->getTrackType() == Track::kTrackTypeAudio) { if (getStreamType(nextTag) != MKTAG16('w', 'b')) error("Invalid audio track tag '%s'", tag2str(nextTag)); assert(chunk); ((AVIAudioTrack *)track)->queueSound(chunk); } else { AVIVideoTrack *videoTrack = (AVIVideoTrack *)track; if (getStreamType(nextTag) == MKTAG16('p', 'c')) { // Palette Change assert(chunk); byte firstEntry = chunk->readByte(); uint16 numEntries = chunk->readByte(); chunk->readUint16LE(); // Reserved // 0 entries means all colors are going to be changed if (numEntries == 0) numEntries = 256; byte *palette = const_cast<byte *>(videoTrack->getPalette()); for (uint16 i = firstEntry; i < numEntries + firstEntry; i++) { palette[i * 3] = chunk->readByte(); palette[i * 3 + 1] = chunk->readByte(); palette[i * 3 + 2] = chunk->readByte(); chunk->readByte(); // Flags that don't serve us any purpose } delete chunk; videoTrack->markPaletteDirty(); } else if (getStreamType(nextTag) == MKTAG16('d', 'b')) { // TODO: Check if this really is uncompressed. Many videos // falsely put compressed data in here. error("Uncompressed AVI frame found"); } else { // Otherwise, assume it's a compressed frame videoTrack->decodeFrame(chunk); } } }
void AVIDecoder::handleStreamHeader(uint32 size) { AVIStreamHeader sHeader; sHeader.size = size; sHeader.streamType = _fileStream->readUint32BE(); if (sHeader.streamType == ID_MIDS || sHeader.streamType == ID_TXTS) error("Unhandled MIDI/Text stream"); sHeader.streamHandler = _fileStream->readUint32BE(); sHeader.flags = _fileStream->readUint32LE(); sHeader.priority = _fileStream->readUint16LE(); sHeader.language = _fileStream->readUint16LE(); sHeader.initialFrames = _fileStream->readUint32LE(); sHeader.scale = _fileStream->readUint32LE(); sHeader.rate = _fileStream->readUint32LE(); sHeader.start = _fileStream->readUint32LE(); sHeader.length = _fileStream->readUint32LE(); sHeader.bufferSize = _fileStream->readUint32LE(); sHeader.quality = _fileStream->readUint32LE(); sHeader.sampleSize = _fileStream->readUint32LE(); _fileStream->skip(sHeader.size - 48); // Skip over the remainder of the chunk (frame) if (_fileStream->readUint32BE() != ID_STRF) error("Could not find STRF tag"); uint32 strfSize = _fileStream->readUint32LE(); uint32 startPos = _fileStream->pos(); if (sHeader.streamType == ID_VIDS) { if (_frameRateOverride != 0) { sHeader.rate = _frameRateOverride.getNumerator(); sHeader.scale = _frameRateOverride.getDenominator(); } BitmapInfoHeader bmInfo; bmInfo.size = _fileStream->readUint32LE(); bmInfo.width = _fileStream->readUint32LE(); bmInfo.height = _fileStream->readUint32LE(); bmInfo.planes = _fileStream->readUint16LE(); bmInfo.bitCount = _fileStream->readUint16LE(); bmInfo.compression = _fileStream->readUint32BE(); bmInfo.sizeImage = _fileStream->readUint32LE(); bmInfo.xPelsPerMeter = _fileStream->readUint32LE(); bmInfo.yPelsPerMeter = _fileStream->readUint32LE(); bmInfo.clrUsed = _fileStream->readUint32LE(); bmInfo.clrImportant = _fileStream->readUint32LE(); if (bmInfo.clrUsed == 0) bmInfo.clrUsed = 256; if (sHeader.streamHandler == 0) sHeader.streamHandler = bmInfo.compression; AVIVideoTrack *track = new AVIVideoTrack(_header.totalFrames, sHeader, bmInfo); if (bmInfo.bitCount == 8) { byte *palette = const_cast<byte *>(track->getPalette()); for (uint32 i = 0; i < bmInfo.clrUsed; i++) { palette[i * 3 + 2] = _fileStream->readByte(); palette[i * 3 + 1] = _fileStream->readByte(); palette[i * 3] = _fileStream->readByte(); _fileStream->readByte(); } track->markPaletteDirty(); } addTrack(track); } else if (sHeader.streamType == ID_AUDS) { PCMWaveFormat wvInfo; wvInfo.tag = _fileStream->readUint16LE(); wvInfo.channels = _fileStream->readUint16LE(); wvInfo.samplesPerSec = _fileStream->readUint32LE(); wvInfo.avgBytesPerSec = _fileStream->readUint32LE(); wvInfo.blockAlign = _fileStream->readUint16LE(); wvInfo.size = _fileStream->readUint16LE(); // AVI seems to treat the sampleSize as including the second // channel as well, so divide for our sake. if (wvInfo.channels == 2) sHeader.sampleSize /= 2; addTrack(new AVIAudioTrack(sHeader, wvInfo, _soundType)); } // Ensure that we're at the end of the chunk _fileStream->seek(startPos + strfSize); }