diff options
Diffstat (limited to 'engines/bladerunner/vqa_decoder.cpp')
-rw-r--r-- | engines/bladerunner/vqa_decoder.cpp | 115 |
1 files changed, 72 insertions, 43 deletions
diff --git a/engines/bladerunner/vqa_decoder.cpp b/engines/bladerunner/vqa_decoder.cpp index 06cba12592..275ec18a4d 100644 --- a/engines/bladerunner/vqa_decoder.cpp +++ b/engines/bladerunner/vqa_decoder.cpp @@ -128,6 +128,9 @@ VQADecoder::VQADecoder(Graphics::Surface *surface) : } VQADecoder::~VQADecoder() { + for (uint i = 0; i < _codebooks.size(); ++i) { + delete[] _codebooks[i].data; + } delete _audioTrack; delete _videoTrack; delete[] _frameInfo; @@ -191,8 +194,9 @@ bool VQADecoder::loadStream(Common::SeekableReadStream *s) { return true; } -void VQADecoder::decodeVideoFrame() { - _videoTrack->decodeVideoFrame(); +void VQADecoder::decodeVideoFrame(int frame, bool forceDraw) { + _decodingFrame = frame; + _videoTrack->decodeVideoFrame(forceDraw); } void VQADecoder::decodeZBuffer(ZBuffer *zbuffer) { @@ -215,7 +219,7 @@ void VQADecoder::decodeLights(Lights *lights) { _videoTrack->decodeLights(lights); } -void VQADecoder::readPacket(int skipFlags) { +void VQADecoder::readPacket(uint readFlags) { IFFChunkHeader chd; if (remain(_s) < 8) { @@ -232,15 +236,15 @@ void VQADecoder::readPacket(int skipFlags) { bool rc = false; // Video track switch (chd.id) { - case kAESC: rc = skipFlags & 1 ? _s->skip(roundup(chd.size)) : _videoTrack->readAESC(_s, chd.size); break; - case kLITE: rc = skipFlags & 1 ? _s->skip(roundup(chd.size)) : _videoTrack->readLITE(_s, chd.size); break; - case kVIEW: rc = skipFlags & 1 ? _s->skip(roundup(chd.size)) : _videoTrack->readVIEW(_s, chd.size); break; - case kVQFL: rc = skipFlags & 1 ? _s->skip(roundup(chd.size)) : _videoTrack->readVQFL(_s, chd.size); break; - case kVQFR: rc = skipFlags & 1 ? _s->skip(roundup(chd.size)) : _videoTrack->readVQFR(_s, chd.size); break; - case kZBUF: rc = skipFlags & 1 ? _s->skip(roundup(chd.size)) : _videoTrack->readZBUF(_s, chd.size); break; + case kAESC: rc = ((readFlags & kVQAReadCustom) == 0) ? _s->skip(roundup(chd.size)) : _videoTrack->readAESC(_s, chd.size); break; + case kLITE: rc = ((readFlags & kVQAReadCustom) == 0) ? _s->skip(roundup(chd.size)) : _videoTrack->readLITE(_s, chd.size); break; + case kVIEW: rc = ((readFlags & kVQAReadCustom) == 0) ? _s->skip(roundup(chd.size)) : _videoTrack->readVIEW(_s, chd.size); break; + case kVQFL: rc = ((readFlags & kVQAReadVideo ) == 0) ? _s->skip(roundup(chd.size)) : _videoTrack->readVQFL(_s, chd.size, readFlags); break; + case kVQFR: rc = ((readFlags & kVQAReadVideo ) == 0) ? _s->skip(roundup(chd.size)) : _videoTrack->readVQFR(_s, chd.size, readFlags); break; + case kZBUF: rc = ((readFlags & kVQAReadCustom) == 0) ? _s->skip(roundup(chd.size)) : _videoTrack->readZBUF(_s, chd.size); break; // Sound track - case kSN2J: rc = skipFlags & 2 ? _s->skip(roundup(chd.size)) : _audioTrack->readSN2J(_s, chd.size); break; - case kSND2: rc = skipFlags & 2 ? _s->skip(roundup(chd.size)) : _audioTrack->readSND2(_s, chd.size); break; + case kSN2J: rc = ((readFlags & kVQAReadAudio) == 0) ? _s->skip(roundup(chd.size)) : _audioTrack->readSN2J(_s, chd.size); break; + case kSND2: rc = ((readFlags & kVQAReadAudio) == 0) ? _s->skip(roundup(chd.size)) : _audioTrack->readSND2(_s, chd.size); break; default: rc = false; _s->skip(roundup(chd.size)); @@ -253,14 +257,16 @@ void VQADecoder::readPacket(int skipFlags) { } while (chd.id != kVQFR); } -void VQADecoder::readFrame(int frame, int skipFlags) { +void VQADecoder::readFrame(int frame, uint readFlags) { if (frame < 0 || frame >= numFrames()) { error("frame %d out of bounds, frame count is %d", frame, numFrames()); } uint32 frameOffset = 2 * (_frameInfo[frame] & 0x0FFFFFFF); _s->seek(frameOffset); - readPacket(skipFlags); + + _readingFrame = frame; + readPacket(readFlags); } bool VQADecoder::readVQHD(Common::SeekableReadStream *s, uint32 size) { @@ -289,10 +295,6 @@ bool VQADecoder::readVQHD(Common::SeekableReadStream *s, uint32 size) { _header.maxCBFZSize = s->readUint32LE(); _header.unk5 = s->readUint32LE(); - if (_header.offsetX || _header.offsetY) { - debug("_header.offsetX, _header.offsetY: %d %d", _header.offsetX, _header.offsetY); - } - // if (_header.unk3 || _header.unk4 != 4 || _header.unk5 || _header.flags != 0x0014) if (false) { debug("_header.version %d", _header.version); @@ -330,7 +332,7 @@ bool VQADecoder::readVQHD(Common::SeekableReadStream *s, uint32 size) { return true; } -bool VQADecoder::VQAVideoTrack::readVQFR(Common::SeekableReadStream *s, uint32 size) { +bool VQADecoder::VQAVideoTrack::readVQFR(Common::SeekableReadStream *s, uint32 size, uint readFlags) { IFFChunkHeader chd; while (size >= 8) { @@ -340,8 +342,8 @@ bool VQADecoder::VQAVideoTrack::readVQFR(Common::SeekableReadStream *s, uint32 s bool rc = false; switch (chd.id) { - case kCBFZ: rc = readCBFZ(s, chd.size); break; - case kVPTR: rc = readVPTR(s, chd.size); break; + case kCBFZ: rc = ((readFlags & kVQAReadCodebook ) == 0) ? s->skip(roundup(chd.size)) : readCBFZ(s, chd.size); break; + case kVPTR: rc = ((readFlags & kVQAReadVectorPointerTable) == 0) ? s->skip(roundup(chd.size)) : readVPTR(s, chd.size); break; default: s->skip(roundup(chd.size)); } @@ -426,6 +428,22 @@ bool VQADecoder::readLINF(Common::SeekableReadStream *s, uint32 size) { return true; } +VQADecoder::CodebookInfo &VQADecoder::codebookInfoForFrame(int frame) { + assert(frame < numFrames()); + assert(!_codebooks.empty()); + + CodebookInfo *ci = nullptr; + uint count = _codebooks.size(); + for (uint i = 0; i != count; ++i) { + if (frame >= _codebooks[count - i - 1].frame) { + return _codebooks[count - i - 1]; + } + } + + assert(ci && "No codebook found"); + return _codebooks[0]; +} + bool VQADecoder::readCINF(Common::SeekableReadStream *s, uint32 size) { IFFChunkHeader chd; @@ -433,17 +451,23 @@ bool VQADecoder::readCINF(Common::SeekableReadStream *s, uint32 size) { if (chd.id != kCINH || chd.size != 8u) return false; - _clipInfo.clipCount = s->readUint16LE(); + uint16 codebookCount = s->readUint16LE(); + _codebooks.resize(codebookCount); + s->skip(6); readIFFChunkHeader(_s, &chd); - if (chd.id != kCIND || chd.size != 6u * _clipInfo.clipCount) + if (chd.id != kCIND || chd.size != 6u * codebookCount) return false; - for (int i = 0; i != _clipInfo.clipCount; ++i) { - uint16 a = s->readUint16LE(); - uint32 b = s->readUint32LE(); - debug("VQADecoder::readCINF() i: %d a: 0x%04x b: 0x%08x", i, a, b); + for (int i = 0; i != codebookCount; ++i) { + _codebooks[i].frame = s->readUint16LE(); + _codebooks[i].size = s->readUint32LE(); + _codebooks[i].data = nullptr; + + // debug("Codebook %2d: %4d %8d", i, _codebooks[i].frame, _codebooks[i].size); + + assert(_codebooks[i].frame < numFrames()); } return true; @@ -543,11 +567,11 @@ bool VQADecoder::readMFCI(Common::SeekableReadStream *s, uint32 size) { } VQADecoder::VQAVideoTrack::VQAVideoTrack(VQADecoder *vqaDecoder, Graphics::Surface *surface) { - VQADecoder::Header *header = &vqaDecoder->_header; - + _vqaDecoder = vqaDecoder; _surface = surface; _hasNewFrame = false; + VQADecoder::Header *header = &vqaDecoder->_header; _numFrames = header->numFrames; _width = header->width; _height = header->height; @@ -562,7 +586,6 @@ VQADecoder::VQAVideoTrack::VQAVideoTrack(VQADecoder *vqaDecoder, Graphics::Surfa _maxCBFZSize = header->maxCBFZSize; _maxZBUFChunkSize = vqaDecoder->_maxZBUFChunkSize; - _codebookSize = 0; _codebook = nullptr; _cbfz = nullptr; _zbufChunk = nullptr; @@ -580,7 +603,6 @@ VQADecoder::VQAVideoTrack::VQAVideoTrack(VQADecoder *vqaDecoder, Graphics::Surfa } VQADecoder::VQAVideoTrack::~VQAVideoTrack() { - delete[] _codebook; delete[] _cbfz; delete[] _zbufChunk; delete[] _vpointer; @@ -598,10 +620,6 @@ uint16 VQADecoder::VQAVideoTrack::getHeight() const { return _height; } -int VQADecoder::VQAVideoTrack::getCurFrame() const { - return _curFrame; -} - int VQADecoder::VQAVideoTrack::getFrameCount() const { return _numFrames; } @@ -610,15 +628,14 @@ Common::Rational VQADecoder::VQAVideoTrack::getFrameRate() const { return _frameRate; } -void VQADecoder::VQAVideoTrack::decodeVideoFrame() { - if (_hasNewFrame) { +void VQADecoder::VQAVideoTrack::decodeVideoFrame(bool forceDraw) { + if (_hasNewFrame || forceDraw) { decodeFrame((uint16*)_surface->getPixels()); - _curFrame++; _hasNewFrame = false; } } -bool VQADecoder::VQAVideoTrack::readVQFL(Common::SeekableReadStream *s, uint32 size) { +bool VQADecoder::VQAVideoTrack::readVQFL(Common::SeekableReadStream *s, uint32 size, uint readFlags) { IFFChunkHeader chd; while (size >= 8) { @@ -648,17 +665,22 @@ bool VQADecoder::VQAVideoTrack::readCBFZ(Common::SeekableReadStream *s, uint32 s return false; } - if (!_codebook) { - _codebookSize = 2 * _maxBlocks * _blockW * _blockH; - _codebook = new uint8[_codebookSize]; + CodebookInfo &codebookInfo = _vqaDecoder->codebookInfoForFrame(_vqaDecoder->_readingFrame); + if (codebookInfo.data) { + s->skip(roundup(size)); + return true; } + + uint32 codebookSize = 2 * _maxBlocks * _blockW * _blockH; + codebookInfo.data = new uint8[codebookSize]; + if (!_cbfz) { _cbfz = new uint8[roundup(_maxCBFZSize)]; } s->read(_cbfz, roundup(size)); - decompress_lcw(_cbfz, size, _codebook, _codebookSize); + decompress_lcw(_cbfz, size, codebookInfo.data, codebookSize); return true; } @@ -790,7 +812,7 @@ void VQADecoder::VQAVideoTrack::VPTRWriteBlock(uint16 *frame, unsigned int dstBl int blocks_per_line = frame_width / block_width; do { - uint32 frame_x = dstBlock % blocks_per_line * block_width + _offsetX / 2; + uint32 frame_x = dstBlock % blocks_per_line * block_width + _offsetX; uint32 frame_y = dstBlock / blocks_per_line * block_height + _offsetY; uint32 dst_offset = frame_x + frame_y * frame_stride; @@ -817,6 +839,13 @@ void VQADecoder::VQAVideoTrack::VPTRWriteBlock(uint16 *frame, unsigned int dstBl } bool VQADecoder::VQAVideoTrack::decodeFrame(uint16 *frame) { + VQADecoder::CodebookInfo &codebookInfo = _vqaDecoder->codebookInfoForFrame(_vqaDecoder->_decodingFrame); + + if (!codebookInfo.data) { + _vqaDecoder->readFrame(codebookInfo.frame, kVQAReadCodebook); + } + + _codebook = codebookInfo.data; if (!_codebook || !_vpointer) return false; |