aboutsummaryrefslogtreecommitdiff
path: root/engines/bladerunner/vqa_decoder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/bladerunner/vqa_decoder.cpp')
-rw-r--r--engines/bladerunner/vqa_decoder.cpp115
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;