diff options
-rw-r--r-- | engines/kyra/vqa.cpp | 470 | ||||
-rw-r--r-- | engines/kyra/vqa.h | 86 |
2 files changed, 280 insertions, 276 deletions
diff --git a/engines/kyra/vqa.cpp b/engines/kyra/vqa.cpp index 975a763715..ab106d40f8 100644 --- a/engines/kyra/vqa.cpp +++ b/engines/kyra/vqa.cpp @@ -60,32 +60,32 @@ static uint32 readTag(Common::SeekableReadStream *stream) { } VQADecoder::VQADecoder() { + memset(&_header, 0, sizeof(_header)); } VQADecoder::~VQADecoder() { close(); + delete[] _frameInfo; } bool VQADecoder::loadStream(Common::SeekableReadStream *stream) { close(); + _fileStream = stream; - if (stream->readUint32BE() != MKTAG('F','O','R','M')) { + if (_fileStream->readUint32BE() != MKTAG('F','O','R','M')) { warning("VQADecoder::loadStream(): Cannot find `FORM' tag"); return false; } // Ignore the size of the FORM chunk. We're only interested in its // children. - stream->readUint32BE(); + _fileStream->readUint32BE(); - if (stream->readUint32BE() != MKTAG('W','V','Q','A')) { + if (_fileStream->readUint32BE() != MKTAG('W','V','Q','A')) { warning("VQADecoder::loadStream(): Cannot find `WVQA' tag"); return false; } - VQAVideoTrack *videoTrack = new VQADecoder::VQAVideoTrack(stream); - addTrack(videoTrack); - // We want to find both a VQHD chunk containing the header, and a FINF // chunk containing the frame offsets. @@ -99,14 +99,13 @@ bool VQADecoder::loadStream(Common::SeekableReadStream *stream) { while (!foundVQHD || !foundFINF) { uint32 tag = readTag(stream); - uint32 size = stream->readUint32BE(); + uint32 size = _fileStream->readUint32BE(); switch (tag) { case MKTAG('V','Q','H','D'): - videoTrack->handleVQHD(); - if (videoTrack->hasSound()) { - audioTrack = new VQAAudioTrack(stream, videoTrack->getAudioFreq()); - videoTrack->setAudioTrack(audioTrack); + handleVQHD(_fileStream); + if (_header.flags & 1) { + audioTrack = new VQAAudioTrack(&_header); addTrack(audioTrack); } foundVQHD = true; @@ -120,12 +119,12 @@ bool VQADecoder::loadStream(Common::SeekableReadStream *stream) { warning("VQADecoder::loadStream(): Expected size %d for `FINF' chunk, but got %u", 4 * getFrameCount(), size); return false; } - videoTrack->handleFINF(); + handleFINF(_fileStream); foundFINF = true; break; default: warning("VQADecoder::loadStream(): Unknown tag `%s'", tag2str(tag)); - stream->seek(size, SEEK_CUR); + _fileStream->seek(size, SEEK_CUR); break; } } @@ -133,11 +132,158 @@ bool VQADecoder::loadStream(Common::SeekableReadStream *stream) { return true; } +void VQADecoder::handleVQHD(Common::SeekableReadStream *stream) { + _header.version = stream->readUint16LE(); + _header.flags = stream->readUint16LE(); + _header.numFrames = stream->readUint16LE(); + _header.width = stream->readUint16LE(); + _header.height = stream->readUint16LE(); + _header.blockW = stream->readByte(); + _header.blockH = stream->readByte(); + _header.frameRate = stream->readByte(); + _header.cbParts = stream->readByte(); + _header.colors = stream->readUint16LE(); + _header.maxBlocks = stream->readUint16LE(); + _header.unk1 = stream->readUint32LE(); + _header.unk2 = stream->readUint16LE(); + _header.freq = stream->readUint16LE(); + _header.channels = stream->readByte(); + _header.bits = stream->readByte(); + _header.unk3 = stream->readUint32LE(); + _header.unk4 = stream->readUint16LE(); + _header.maxCBFZSize = stream->readUint32LE(); + _header.unk5 = stream->readUint32LE(); + + _frameInfo = new uint32[_header.numFrames + 1]; + + VQAVideoTrack *videoTrack = new VQAVideoTrack(&_header); + addTrack(videoTrack); + + // Kyrandia 3 uses version 1 VQA files, and is the only known game to + // do so. This version of the format has some implicit default values. + + if (_header.version == 1) { + if (_header.freq == 0) + _header.freq = 22050; + if (_header.channels == 0) + _header.channels = 1; + if (_header.bits == 0) + _header.bits = 8; + } + + if (_header.flags & 1) { + // Kyrandia 3 uses 8-bit sound, and so far testing indicates + // that it's all mono. + // + // This is good, because it means we won't have to worry about + // the confusing parts of the VQA spec, where 8- and 16-bit + // data have different signedness and stereo sample layout + // varies between different games. + + assert(_header.bits == 8); + assert(_header.channels == 1); + } +} + +void VQADecoder::handleFINF(Common::SeekableReadStream *stream) { + for (int i = 0; i < _header.numFrames; i++) { + _frameInfo[i] = 2 * stream->readUint32LE(); + } + + // HACK: This flag is set in jung2.vqa, and its purpose - if it has + // one - is currently unknown. It can't be a general purpose flag, + // because in large movies the frame offset can be large enough to + // set this flag, though of course never for the first frame. + // + // At least in my copy of Kyrandia 3, _frameInfo[0] is 0x81000098, and + // the desired index is 0x4716. So the value should be 0x80004716, but + // I don't want to hard-code it. Instead, scan the file for the offset + // to the first VQFR chunk. + + if (_frameInfo[0] & 0x01000000) { + uint32 oldPos = stream->pos(); + + while (1) { + uint32 scanTag = readTag(stream); + uint32 scanSize = stream->readUint32BE(); + + if (stream->eos()) + break; + + if (scanTag == MKTAG('V','Q','F','R')) { + _frameInfo[0] = (stream->pos() - 8) | 0x80000000; + break; + } + + stream->seek(scanSize, SEEK_CUR); + } + + stream->seek(oldPos); + } + + _frameInfo[_header.numFrames] = 0x7FFFFFFF; +} + +void VQADecoder::readNextPacket() { + VQAVideoTrack *videoTrack = (VQAVideoTrack *)getTrack(0); + VQAAudioTrack *audioTrack = (VQAAudioTrack *)getTrack(1); + + assert(videoTrack); + + int curFrame = videoTrack->getCurFrame(); + + // Stop if reading the tag is enough to put us ahead of the next frame + int32 end = (_frameInfo[curFrame + 1] & 0x7FFFFFFF) - 7; + + // At this point, we probably only need to adjust for the offset in the + // stream to be even. But we may as well do this to really make sure + // we have the correct offset. + if (curFrame >= 0) { + _fileStream->seek(_frameInfo[curFrame] & 0x7FFFFFFF); + if (_frameInfo[curFrame] & 0x80000000) { + videoTrack->setHasDirtyPalette(); + } + } + + while (!_fileStream->eos() && _fileStream->pos() < end) { + uint32 tag = readTag(_fileStream); + uint32 size; + + switch (tag) { + case MKTAG('S','N','D','0'): // Uncompressed sound + assert(audioTrack); + audioTrack->handleSND0(_fileStream); + break; + case MKTAG('S','N','D','1'): // Compressed sound, almost like AUD + assert(audioTrack); + audioTrack->handleSND1(_fileStream); + break; + case MKTAG('S','N','D','2'): // Compressed sound + assert(audioTrack); + audioTrack->handleSND2(_fileStream); + break; + case MKTAG('V','Q','F','R'): + videoTrack->handleVQFR(_fileStream); + break; + case MKTAG('C','M','D','S'): + // The purpose of this is unknown, but it's known to + // exist so don't warn about it. + size = _fileStream->readUint32BE(); + _fileStream->seek(size, SEEK_CUR); + break; + default: + warning("VQADecoder::readNextPacket(): Unknown tag `%s'", tag2str(tag)); + size = _fileStream->readUint32BE(); + _fileStream->seek(size, SEEK_CUR); + break; + } + } +} + // ----------------------------------------------------------------------- -VQADecoder::VQAAudioTrack::VQAAudioTrack(Common::SeekableReadStream *stream, int freq) { - _fileStream = stream; - _audioStream = Audio::makeQueuingAudioStream(freq, false); +VQADecoder::VQAAudioTrack::VQAAudioTrack(VQAHeader *header) { + _audioStream = Audio::makeQueuingAudioStream(header->freq, false); } VQADecoder::VQAAudioTrack::~VQAAudioTrack() { @@ -148,20 +294,20 @@ Audio::AudioStream *VQADecoder::VQAAudioTrack::getAudioStream() const { return _audioStream; } -void VQADecoder::VQAAudioTrack::handleSND0() { - uint32 size = _fileStream->readUint32BE(); +void VQADecoder::VQAAudioTrack::handleSND0(Common::SeekableReadStream *stream) { + uint32 size = stream->readUint32BE(); byte *buf = (byte *)malloc(size); - _fileStream->read(buf, size); + stream->read(buf, size); _audioStream->queueBuffer(buf, size, DisposeAfterUse::YES, Audio::FLAG_UNSIGNED); } -void VQADecoder::VQAAudioTrack::handleSND1() { - _fileStream->readUint32BE(); - uint16 outsize = _fileStream->readUint16LE(); - uint16 insize = _fileStream->readUint16LE(); +void VQADecoder::VQAAudioTrack::handleSND1(Common::SeekableReadStream *stream) { + stream->readUint32BE(); + uint16 outsize = stream->readUint16LE(); + uint16 insize = stream->readUint16LE(); byte *inbuf = (byte *)malloc(insize); - _fileStream->read(inbuf, insize); + stream->read(inbuf, insize); if (insize == outsize) { _audioStream->queueBuffer(inbuf, insize, DisposeAfterUse::YES, Audio::FLAG_UNSIGNED); @@ -241,50 +387,61 @@ void VQADecoder::VQAAudioTrack::handleSND1() { } } -void VQADecoder::VQAAudioTrack::handleSND2() { - uint32 size = _fileStream->readUint32BE(); +void VQADecoder::VQAAudioTrack::handleSND2(Common::SeekableReadStream *stream) { + uint32 size = stream->readUint32BE(); warning("VQADecoder::VQAAudioTrack::handleSND2(): `SND2' is not implemented"); - _fileStream->seek(size, SEEK_CUR); + stream->seek(size, SEEK_CUR); } // ----------------------------------------------------------------------- -VQADecoder::VQAVideoTrack::VQAVideoTrack(Common::SeekableReadStream *stream) { - _fileStream = stream; - _surface = new Graphics::Surface(); +VQADecoder::VQAVideoTrack::VQAVideoTrack(VQAHeader *header) { memset(_palette, 0, sizeof(_palette)); _dirtyPalette = false; - _audioTrack = NULL; + + _width = header->width; + _height = header->height; + _blockW = header->blockW; + _blockH = header->blockH; + _cbParts = header->cbParts; + + _newFrame = false; _curFrame = -1; + _frameCount = header->numFrames; + _frameRate = header->frameRate; - memset(&_header, 0, sizeof(_header)); - _frameInfo = NULL; - _codeBookSize = 0; + _codeBookSize = 0xF00 * header->blockW * header->blockH; _compressedCodeBook = false; - _codeBook = NULL; + _codeBook = new byte[_codeBookSize]; _partialCodeBookSize = 0; _numPartialCodeBooks = 0; - _partialCodeBook = NULL; - _numVectorPointers = 0; - _vectorPointers = NULL; + _partialCodeBook = new byte[_codeBookSize]; + _numVectorPointers = (header->width / header->blockW) * (header->height * header->blockH); + _vectorPointers = new uint16[_numVectorPointers]; + + memset(_codeBook, 0, _codeBookSize); + memset(_partialCodeBook, 0, _codeBookSize); + memset(_vectorPointers, 0, _numVectorPointers); + + _surface = new Graphics::Surface(); + _surface->create(header->width, header->height, Graphics::PixelFormat::createFormatCLUT8()); } VQADecoder::VQAVideoTrack::~VQAVideoTrack() { + _surface->free(); delete _surface; - delete[] _frameInfo; delete[] _codeBook; delete[] _partialCodeBook; delete[] _vectorPointers; - // The audio track gets deleted by VQADecoder. } uint16 VQADecoder::VQAVideoTrack::getWidth() const { - return _header.width; + return _width; } uint16 VQADecoder::VQAVideoTrack::getHeight() const { - return _header.height; + return _height; } Graphics::PixelFormat VQADecoder::VQAVideoTrack::getPixelFormat() const { @@ -296,19 +453,15 @@ int VQADecoder::VQAVideoTrack::getCurFrame() const { } int VQADecoder::VQAVideoTrack::getFrameCount() const { - return _header.numFrames; + return _frameCount; } Common::Rational VQADecoder::VQAVideoTrack::getFrameRate() const { - return _header.frameRate; -} - -bool VQADecoder::VQAVideoTrack::hasSound() const { - return (_header.flags & 1) != 0; + return _frameRate; } -int VQADecoder::VQAVideoTrack::getAudioFreq() const { - return _header.freq; +void VQADecoder::VQAVideoTrack::setHasDirtyPalette() { + _dirtyPalette = true; } bool VQADecoder::VQAVideoTrack::hasDirtyPalette() const { @@ -320,93 +473,40 @@ const byte *VQADecoder::VQAVideoTrack::getPalette() const { return _palette; } -void VQADecoder::VQAVideoTrack::setAudioTrack(VQAAudioTrack *audioTrack) { - _audioTrack = audioTrack; -} - const Graphics::Surface *VQADecoder::VQAVideoTrack::decodeNextFrame() { - // Stop if reading the tag is enough to put us ahead of the next frame - int32 end = (_frameInfo[_curFrame + 1] & 0x7FFFFFFF) - 7; - - // At this point, we probably only need to adjust for the offset in the - // stream to be even. But we may as well do this to really make sure - // we have the correct offset. - if (_curFrame >= 0) { - _fileStream->seek(_frameInfo[_curFrame] & 0x7FFFFFFF); - } - - bool hasFrame = false; + if (_newFrame) { + _newFrame = false; - while (!_fileStream->eos() && _fileStream->pos() < end) { - uint32 tag = readTag(_fileStream); - uint32 size; + int blockPitch = _width / _blockW; - switch (tag) { - case MKTAG('S','N','D','0'): // Uncompressed sound - assert(_audioTrack); - _audioTrack->handleSND0(); - break; - case MKTAG('S','N','D','1'): // Compressed sound, almost like AUD - assert(_audioTrack); - _audioTrack->handleSND1(); - break; - case MKTAG('S','N','D','2'): // Compressed sound - assert(_audioTrack); - _audioTrack->handleSND2(); - break; - case MKTAG('V','Q','F','R'): - handleVQFR(); - hasFrame = true; - break; - case MKTAG('C','M','D','S'): - // The purpose of this is unknown, but it's known to - // exist so don't warn about it. - size = _fileStream->readUint32BE(); - _fileStream->seek(size, SEEK_CUR); - break; - default: - warning("VQADecoder::VQAVideoTrack::decodeNextFrame(): Unknown tag `%s'", tag2str(tag)); - size = _fileStream->readUint32BE(); - _fileStream->seek(size, SEEK_CUR); - break; - } - } - - if (hasFrame) { - if (_frameInfo[_curFrame] & 0x80000000) { - _dirtyPalette = true; - } - - int blockPitch = _header.width / _header.blockW; - - for (int by = 0; by < _header.height / _header.blockH; by++) { + for (int by = 0; by < _height / _blockH; by++) { for (int bx = 0; bx < blockPitch; bx++) { - byte *dst = (byte *)_surface->getBasePtr(bx * _header.blockW, by * _header.blockH); + byte *dst = (byte *)_surface->getBasePtr(bx * _blockW, by * _blockH); int val = _vectorPointers[by * blockPitch + bx]; int i; if ((val & 0xFF00) == 0xFF00) { // Solid color - for (i = 0; i < _header.blockH; i++) { - memset(dst, 255 - (val & 0xFF), _header.blockW); - dst += _header.width; + for (i = 0; i < _blockH; i++) { + memset(dst, 255 - (val & 0xFF), _blockW); + dst += _width; } } else { // Copy data from _vectorPointers. I'm not sure // why we don't use the three least significant // bits of 'val'. - byte *src = &_codeBook[(val >> 3) * _header.blockW * _header.blockH]; + byte *src = &_codeBook[(val >> 3) * _blockW * _blockH]; - for (i = 0; i < _header.blockH; i++) { - memcpy(dst, src, _header.blockW); - src += _header.blockW; - dst += _header.width; + for (i = 0; i < _blockH; i++) { + memcpy(dst, src, _blockW); + src += _blockW; + dst += _width; } } } } - if (_numPartialCodeBooks == _header.cbParts) { + if (_numPartialCodeBooks == _cbParts) { if (_compressedCodeBook) { Screen::decodeFrame4(_partialCodeBook, _codeBook, _codeBookSize); } else { @@ -421,160 +521,58 @@ const Graphics::Surface *VQADecoder::VQAVideoTrack::decodeNextFrame() { return _surface; } -void VQADecoder::VQAVideoTrack::handleVQHD() { - _header.version = _fileStream->readUint16LE(); - _header.flags = _fileStream->readUint16LE(); - _header.numFrames = _fileStream->readUint16LE(); - _header.width = _fileStream->readUint16LE(); - _header.height = _fileStream->readUint16LE(); - _header.blockW = _fileStream->readByte(); - _header.blockH = _fileStream->readByte(); - _header.frameRate = _fileStream->readByte(); - _header.cbParts = _fileStream->readByte(); - _header.colors = _fileStream->readUint16LE(); - _header.maxBlocks = _fileStream->readUint16LE(); - _header.unk1 = _fileStream->readUint32LE(); - _header.unk2 = _fileStream->readUint16LE(); - _header.freq = _fileStream->readUint16LE(); - _header.channels = _fileStream->readByte(); - _header.bits = _fileStream->readByte(); - _header.unk3 = _fileStream->readUint32LE(); - _header.unk4 = _fileStream->readUint16LE(); - _header.maxCBFZSize = _fileStream->readUint32LE(); - _header.unk5 = _fileStream->readUint32LE(); - - _surface->create(_header.width, _header.height, Graphics::PixelFormat::createFormatCLUT8()); - - // Kyrandia 3 uses version 1 VQA files, and is the only known game to - // do so. This version of the format has some implicit default values. - - if (_header.version == 1) { - if (_header.freq == 0) - _header.freq = 22050; - if (_header.channels == 0) - _header.channels = 1; - if (_header.bits == 0) - _header.bits = 8; - } - - _frameInfo = new uint32[_header.numFrames + 1]; - - _codeBookSize = 0xF00 * _header.blockW * _header.blockH; - _codeBook = new byte[_codeBookSize]; - _partialCodeBook = new byte[_codeBookSize]; - memset(_codeBook, 0, _codeBookSize); - memset(_partialCodeBook, 0, _codeBookSize); - - _numVectorPointers = (_header.width / _header.blockW) * (_header.height * _header.blockH); - _vectorPointers = new uint16[_numVectorPointers]; - memset(_vectorPointers, 0, _numVectorPointers * sizeof(uint16)); - - _partialCodeBookSize = 0; - _numPartialCodeBooks = 0; - - if (hasSound()) { - // Kyrandia 3 uses 8-bit sound, and so far testing indicates - // that it's all mono. - // - // This is good, because it means we won't have to worry about - // the confusing parts of the VQA spec, where 8- and 16-bit - // data have different signedness and stereo sample layout - // varies between different games. - - assert(_header.bits == 8); - assert(_header.channels == 1); - } -} - -void VQADecoder::VQAVideoTrack::handleFINF() { - for (int i = 0; i < _header.numFrames; i++) { - _frameInfo[i] = 2 * _fileStream->readUint32LE(); - } - - // HACK: This flag is set in jung2.vqa, and its purpose - if it has - // one - is currently unknown. It can't be a general purpose flag, - // because in large movies the frame offset can be large enough to - // set this flag, though of course never for the first frame. - // - // At least in my copy of Kyrandia 3, _frameInfo[0] is 0x81000098, and - // the desired index is 0x4716. So the value should be 0x80004716, but - // I don't want to hard-code it. Instead, scan the file for the offset - // to the first VQFR chunk. - - if (_frameInfo[0] & 0x01000000) { - uint32 oldPos = _fileStream->pos(); - - while (1) { - uint32 scanTag = readTag(_fileStream); - uint32 scanSize = _fileStream->readUint32BE(); - - if (_fileStream->eos()) - break; - - if (scanTag == MKTAG('V','Q','F','R')) { - _frameInfo[0] = (_fileStream->pos() - 8) | 0x80000000; - break; - } - - _fileStream->seek(scanSize, SEEK_CUR); - } - - _fileStream->seek(oldPos); - } - - _frameInfo[_header.numFrames] = 0x7FFFFFFF; -} - -void VQADecoder::VQAVideoTrack::handleVQFR() { - uint32 size = _fileStream->readUint32BE(); - int32 end = _fileStream->pos() + size - 8; +void VQADecoder::VQAVideoTrack::handleVQFR(Common::SeekableReadStream *stream) { + uint32 size = stream->readUint32BE(); + int32 end = stream->pos() + size - 8; byte *inbuf; - while (_fileStream->pos() < end) { - uint32 tag = readTag(_fileStream); + _newFrame = true; + + while (stream->pos() < end) { + uint32 tag = readTag(stream); uint32 i; - size = _fileStream->readUint32BE(); + size = stream->readUint32BE(); switch (tag) { case MKTAG('C','B','F','0'): // Full codebook - _fileStream->read(_codeBook, size); + stream->read(_codeBook, size); break; case MKTAG('C','B','F','Z'): // Full codebook inbuf = (byte *)malloc(size); - _fileStream->read(inbuf, size); + stream->read(inbuf, size); Screen::decodeFrame4(inbuf, _codeBook, _codeBookSize); free(inbuf); break; case MKTAG('C','B','P','0'): // Partial codebook _compressedCodeBook = false; - _fileStream->read(_partialCodeBook + _partialCodeBookSize, size); + stream->read(_partialCodeBook + _partialCodeBookSize, size); _partialCodeBookSize += size; _numPartialCodeBooks++; break; case MKTAG('C','B','P','Z'): // Partial codebook _compressedCodeBook = true; - _fileStream->read(_partialCodeBook + _partialCodeBookSize, size); + stream->read(_partialCodeBook + _partialCodeBookSize, size); _partialCodeBookSize += size; _numPartialCodeBooks++; break; case MKTAG('C','P','L','0'): // Palette assert(size <= 3 * 256); - _fileStream->read(_palette, size); + stream->read(_palette, size); break; case MKTAG('C','P','L','Z'): // Palette inbuf = (byte *)malloc(size); - _fileStream->read(inbuf, size); + stream->read(inbuf, size); Screen::decodeFrame4(inbuf, _palette, 3 * 256); free(inbuf); break; case MKTAG('V','P','T','0'): // Frame data assert(size / 2 <= _numVectorPointers); for (i = 0; i < size / 2; i++) - _vectorPointers[i] = _fileStream->readUint16LE(); + _vectorPointers[i] = stream->readUint16LE(); break; case MKTAG('V','P','T','Z'): // Frame data inbuf = (byte *)malloc(size); - _fileStream->read(inbuf, size); + stream->read(inbuf, size); size = Screen::decodeFrame4(inbuf, (uint8 *)_vectorPointers, 2 * _numVectorPointers); for (i = 0; i < size / 2; i++) _vectorPointers[i] = TO_LE_16(_vectorPointers[i]); @@ -582,7 +580,7 @@ void VQADecoder::VQAVideoTrack::handleVQFR() { break; default: warning("VQADecoder::VQAVideoTrack::handleVQFR(): Unknown `VQFR' sub-tag `%s'", tag2str(tag)); - _fileStream->seek(size, SEEK_CUR); + stream->seek(size, SEEK_CUR); break; } } diff --git a/engines/kyra/vqa.h b/engines/kyra/vqa.h index 44d1354f3d..02414819db 100644 --- a/engines/kyra/vqa.h +++ b/engines/kyra/vqa.h @@ -44,28 +44,59 @@ public: virtual ~VQADecoder(); bool loadStream(Common::SeekableReadStream *stream); + void readNextPacket(); private: + Common::SeekableReadStream *_fileStream; + + void handleVQHD(Common::SeekableReadStream *stream); + void handleFINF(Common::SeekableReadStream *stream); + + struct VQAHeader { + uint16 version; + uint16 flags; + uint16 numFrames; + uint16 width; + uint16 height; + uint8 blockW; + uint8 blockH; + uint8 frameRate; + uint8 cbParts; + uint16 colors; + uint16 maxBlocks; + uint32 unk1; + uint16 unk2; + uint16 freq; + uint8 channels; + uint8 bits; + uint32 unk3; + uint16 unk4; + uint32 maxCBFZSize; + uint32 unk5; + }; + + VQAHeader _header; + uint32 *_frameInfo; + class VQAAudioTrack : public AudioTrack { public: - VQAAudioTrack(Common::SeekableReadStream *stream, int freq); + VQAAudioTrack(VQAHeader *header); ~VQAAudioTrack(); - void handleSND0(); - void handleSND1(); - void handleSND2(); + void handleSND0(Common::SeekableReadStream *stream); + void handleSND1(Common::SeekableReadStream *stream); + void handleSND2(Common::SeekableReadStream *stream); protected: Audio::AudioStream *getAudioStream() const; private: Audio::QueuingAudioStream *_audioStream; - Common::SeekableReadStream *_fileStream; }; class VQAVideoTrack : public FixedRateVideoTrack { public: - VQAVideoTrack(Common::SeekableReadStream *stream); + VQAVideoTrack(VQAHeader *header); ~VQAVideoTrack(); uint16 getWidth() const; @@ -75,54 +106,29 @@ private: int getFrameCount() const; const Graphics::Surface *decodeNextFrame(); - bool hasSound() const; - int getAudioFreq() const; + void setHasDirtyPalette(); bool hasDirtyPalette() const; const byte *getPalette() const; - void setAudioTrack(VQAAudioTrack *audioTrack); - - void handleVQHD(); - void handleFINF(); - void handleVQFR(); + void handleVQFR(Common::SeekableReadStream *stream); protected: Common::Rational getFrameRate() const; private: - Common::SeekableReadStream *_fileStream; Graphics::Surface *_surface; byte _palette[3 * 256]; mutable bool _dirtyPalette; - VQAAudioTrack *_audioTrack; + bool _newFrame; + + uint16 _width, _height; + uint8 _blockW, _blockH; + uint8 _cbParts; + int _frameCount; int _curFrame; + byte _frameRate; - struct VQAHeader { - uint16 version; - uint16 flags; - uint16 numFrames; - uint16 width; - uint16 height; - uint8 blockW; - uint8 blockH; - uint8 frameRate; - uint8 cbParts; - uint16 colors; - uint16 maxBlocks; - uint32 unk1; - uint16 unk2; - uint16 freq; - uint8 channels; - uint8 bits; - uint32 unk3; - uint16 unk4; - uint32 maxCBFZSize; - uint32 unk5; - }; - - VQAHeader _header; - uint32 *_frameInfo; uint32 _codeBookSize; bool _compressedCodeBook; byte *_codeBook; |