diff options
author | Thomas Fach-Pedersen | 2014-05-24 12:15:17 +0200 |
---|---|---|
committer | Eugene Sandulenko | 2016-09-29 22:33:17 +0200 |
commit | 8217ed6065ac0c45edaeb672908da7e91a068c4f (patch) | |
tree | 482836c5bde6dcc83e09f9e4f2dbecdb5e7f12d5 /engines | |
parent | a67e9e16bdbb5acbb2d1eb52a87c3eb2d128c44d (diff) | |
download | scummvm-rg350-8217ed6065ac0c45edaeb672908da7e91a068c4f.tar.gz scummvm-rg350-8217ed6065ac0c45edaeb672908da7e91a068c4f.tar.bz2 scummvm-rg350-8217ed6065ac0c45edaeb672908da7e91a068c4f.zip |
BLADERUNNER: Don't base VQADecoder on Video::VideoDecoder anyway
VideoDecoder doesn't handle audio underflow very well,
and Blade Runner's VQA files don't have any audio prebuffer.
VQAPlayer doesn't handle it perfectly either, but underflow
happens a lot less. To be improved.
Diffstat (limited to 'engines')
-rw-r--r-- | engines/bladerunner/module.mk | 3 | ||||
-rw-r--r-- | engines/bladerunner/outtake.cpp | 34 | ||||
-rw-r--r-- | engines/bladerunner/vqa_decoder.cpp | 64 | ||||
-rw-r--r-- | engines/bladerunner/vqa_decoder.h | 55 | ||||
-rw-r--r-- | engines/bladerunner/vqa_player.cpp | 125 | ||||
-rw-r--r-- | engines/bladerunner/vqa_player.h | 19 |
6 files changed, 161 insertions, 139 deletions
diff --git a/engines/bladerunner/module.mk b/engines/bladerunner/module.mk index 23113a9a60..b1de94deae 100644 --- a/engines/bladerunner/module.mk +++ b/engines/bladerunner/module.mk @@ -12,7 +12,8 @@ MODULE_OBJS = \ image.o \ outtake.o \ settings.o \ - vqa_decoder.o + vqa_decoder.o \ + vqa_player.o # This module can be built as a plugin ifeq ($(ENABLE_BLADERUNNER), DYNAMIC_PLUGIN) diff --git a/engines/bladerunner/outtake.cpp b/engines/bladerunner/outtake.cpp index 6ebede5663..3bbcb6b729 100644 --- a/engines/bladerunner/outtake.cpp +++ b/engines/bladerunner/outtake.cpp @@ -23,7 +23,9 @@ #include "bladerunner/outtake.h" #include "bladerunner/bladerunner.h" -#include "bladerunner/vqa_decoder.h" +#include "bladerunner/vqa_player.h" + +#include "audio/audiostream.h" #include "common/debug.h" #include "common/events.h" @@ -43,31 +45,27 @@ void OuttakePlayer::play(const Common::String &name, bool noLocalization, int co else resName = name + "_E.VQA"; - Common::SeekableReadStream *s = _vm->getResourceStream(resName); - - _vqaDecoder = new VQADecoder(); - _vqaDecoder->loadStream(s); + VQAPlayer vqa_player(_vm); - _vqaDecoder->start(); + vqa_player.open(resName); - uint32 last = _vm->_system->getMillis(); + _vm->_mixer->stopAll(); + while (!_vm->shouldQuit()) { + Common::Event event; + while (_vm->_system->getEventManager()->pollEvent(event)) + if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || event.type == Common::EVENT_LBUTTONUP) + return; - while (!_vqaDecoder->endOfVideo() && !_vm->shouldQuit()) { - if (_vqaDecoder->needsUpdate()) { - uint32 now = _vm->_system->getMillis(); - debug("delta: %d", now - last); - last = now; + int frame = vqa_player.update(); + if (frame == -3) + break; - const Graphics::Surface *surface = _vqaDecoder->decodeNextFrame(); + if (frame >= 0) { + const Graphics::Surface *surface = vqa_player.getSurface(); _vm->_system->copyRectToScreen((const byte *)surface->getBasePtr(0, 0), surface->pitch, 0, 0, 640, 480); _vm->_system->updateScreen(); } - Common::Event event; - while (_vm->_system->getEventManager()->pollEvent(event)) - if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || event.type == Common::EVENT_LBUTTONUP) - return; - _vm->_system->delayMillis(10); } } diff --git a/engines/bladerunner/vqa_decoder.cpp b/engines/bladerunner/vqa_decoder.cpp index bd898bc171..bcba7d06b8 100644 --- a/engines/bladerunner/vqa_decoder.cpp +++ b/engines/bladerunner/vqa_decoder.cpp @@ -128,7 +128,7 @@ VQADecoder::~VQADecoder() { } bool VQADecoder::loadStream(Common::SeekableReadStream *s) { - close(); + // close(); _s = s; IFFChunkHeader chd; @@ -160,22 +160,22 @@ bool VQADecoder::loadStream(Common::SeekableReadStream *s) { case kMSCI: rc = readMSCI(s, chd.size); break; case kVQHD: rc = readVQHD(s, chd.size); break; default: - debug("Unhandled chunk '%s'", strTag(chd.id)); + warning("Unhandled chunk '%s'", strTag(chd.id)); s->skip(roundup(chd.size)); rc = true; } if (!rc) { - debug("failed to handle chunk %s", strTag(chd.id)); + warning("failed to handle chunk %s", strTag(chd.id)); return false; } } while (chd.id != kFINF); _videoTrack = new VQAVideoTrack(this); - addTrack(_videoTrack); + // addTrack(_videoTrack); _audioTrack = new VQAAudioTrack(this); - addTrack(_audioTrack); + // addTrack(_audioTrack); /* for (int i = 0; i != _loopInfo.loopCount; ++i) { @@ -189,6 +189,14 @@ bool VQADecoder::loadStream(Common::SeekableReadStream *s) { return true; } +const Graphics::Surface *VQADecoder::decodeVideoFrame() { + return _videoTrack->decodeVideoFrame(); +} + +Audio::SeekableAudioStream *VQADecoder::decodeAudioFrame() { + return _audioTrack->decodeAudioFrame(); +} + void VQADecoder::readNextPacket() { IFFChunkHeader chd; @@ -286,6 +294,12 @@ bool VQADecoder::readVQHD(Common::SeekableReadStream *s, uint32 size) debug("_header.unk5 %d", _header.unk5); } + assert(_header.version == 2); + assert(_header.freq == 22050); + assert(_header.channels == 1); + assert(_header.bits == 16); + assert(_header.colors == 0); + return true; } @@ -345,18 +359,18 @@ bool VQADecoder::readMSCI(Common::SeekableReadStream *s, uint32 size) { case kVIEW: _maxVIEWChunkSize = size; - debug("max VIEW size: %08x", _maxVIEWChunkSize); + // debug("max VIEW size: %08x", _maxVIEWChunkSize); break; case kZBUF: _maxZBUFChunkSize = size; - debug("max ZBUF size: %08x", _maxZBUFChunkSize); + // debug("max ZBUF size: %08x", _maxZBUFChunkSize); break; case kAESC: _maxAESCChunkSize = size; - debug("max AESC size: %08x", _maxAESCChunkSize); + // debug("max AESC size: %08x", _maxAESCChunkSize); break; default: - debug("Unknown tag in MSCT: %s", strTag(tag)); + warning("Unknown tag in MSCT: %s", strTag(tag)); } uint32 zero; @@ -483,7 +497,7 @@ bool VQADecoder::readLNIN(Common::SeekableReadStream *s, uint32 size) for (int i = 0; i != loopNamesCount; ++i) { char *begin = names + loopNameOffsets[i]; - size_t len = ((i == loopNamesCount) ? chd.size : loopNameOffsets[i+1]) - loopNameOffsets[i]; + uint32 len = ((i == loopNamesCount) ? chd.size : loopNameOffsets[i+1]) - loopNameOffsets[i]; _loopInfo.loops[i].name = Common::String(begin, len); } @@ -571,8 +585,7 @@ Common::Rational VQADecoder::VQAVideoTrack::getFrameRate() const { return _frameRate; } -const Graphics::Surface *VQADecoder::VQAVideoTrack::decodeNextFrame() { - debug("_curFrame: %d", _curFrame); +const Graphics::Surface *VQADecoder::VQAVideoTrack::decodeVideoFrame() { if (_hasNewFrame) { decodeFrame((uint16*)_surface->getPixels()); _curFrame++; @@ -607,7 +620,7 @@ bool VQADecoder::VQAVideoTrack::readVQFL(Common::SeekableReadStream *s, uint32 s bool VQADecoder::VQAVideoTrack::readCBFZ(Common::SeekableReadStream *s, uint32 size) { if (size > _maxCBFZSize) { - debug("%d > %d", size, _maxCBFZSize); + warning("readCBFZ: chunk too large: %d > %d", size, _maxCBFZSize); return false; } @@ -871,7 +884,7 @@ bool VQADecoder::VQAVideoTrack::decodeFrame(uint16 *frame) dstBlock += count; break; default: - debug("Undefined case %d", command >> 13); + warning("VQAVideoTrack::decodeFrame: Undefined case %d", command >> 13); } } @@ -879,33 +892,32 @@ bool VQADecoder::VQAVideoTrack::decodeFrame(uint16 *frame) } VQADecoder::VQAAudioTrack::VQAAudioTrack(VQADecoder *vqaDecoder) { - _audioStream = Audio::makeQueuingAudioStream(vqaDecoder->_header.freq, false); + _frequency = vqaDecoder->_header.freq; } VQADecoder::VQAAudioTrack::~VQAAudioTrack() { - delete _audioStream; } -Audio::AudioStream *VQADecoder::VQAAudioTrack::getAudioStream() const { - return _audioStream; +Audio::SeekableAudioStream *VQADecoder::VQAAudioTrack::decodeAudioFrame() { + int16 *audioFrame = (int16*)malloc(4 * 735); + memset(audioFrame, 0, 4 * 735); + + _adpcmDecoder.decode(_compressedAudioFrame, 735, audioFrame); + + uint flags = Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN; + + return Audio::makeRawStream((byte*)audioFrame, 4 * 735, _frequency, flags, DisposeAfterUse::YES); } bool VQADecoder::VQAAudioTrack::readSND2(Common::SeekableReadStream *s, uint32 size) { if (size != 735) { - error("audio frame size: %d", size); + warning("audio frame size: %d", size); return false; } s->read(_compressedAudioFrame, roundup(size)); - int16 *audioFrame = (int16*)malloc(4 * size); - memset(audioFrame, 0, 4 * size); - - _adpcmDecoder.decode(_compressedAudioFrame, size, audioFrame); - - _audioStream->queueBuffer((byte*)audioFrame, 4 * size, DisposeAfterUse::YES, Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN); - return true; } diff --git a/engines/bladerunner/vqa_decoder.h b/engines/bladerunner/vqa_decoder.h index a2237cc1fa..13097c6f11 100644 --- a/engines/bladerunner/vqa_decoder.h +++ b/engines/bladerunner/vqa_decoder.h @@ -38,7 +38,7 @@ namespace BladeRunner { -class VQADecoder : public Video::VideoDecoder +class VQADecoder { public: VQADecoder(); @@ -46,9 +46,21 @@ public: bool loadStream(Common::SeekableReadStream *s); -protected: void readNextPacket(); + const Graphics::Surface *decodeVideoFrame(); + Audio::SeekableAudioStream *decodeAudioFrame(); + + uint16 numFrames() const { return _header.numFrames; } + uint8 frameRate() const { return _header.frameRate; } + + uint16 offsetX() const { return _header.offsetX; } + uint16 offsetY() const { return _header.offsetY; } + + uint16 frequency() const { return _header.freq; } + +protected: + private: struct Header { @@ -121,9 +133,6 @@ private: VQAVideoTrack *_videoTrack; VQAAudioTrack *_audioTrack; - // bool _hasView; - // view_t view; - bool readVQHD(Common::SeekableReadStream *s, uint32 size); bool readMSCI(Common::SeekableReadStream *s, uint32 size); bool readMFCI(Common::SeekableReadStream *s, uint32 size); @@ -133,7 +142,7 @@ private: bool readLNIN(Common::SeekableReadStream *s, uint32 size); bool readCLIP(Common::SeekableReadStream *s, uint32 size); - class VQAVideoTrack : public FixedRateVideoTrack { + class VQAVideoTrack { public: VQAVideoTrack(VQADecoder *vqaDecoder); ~VQAVideoTrack(); @@ -143,7 +152,7 @@ private: Graphics::PixelFormat getPixelFormat() const; int getCurFrame() const; int getFrameCount() const; - const Graphics::Surface *decodeNextFrame(); + const Graphics::Surface *decodeVideoFrame(); bool readVQFR(Common::SeekableReadStream *s, uint32 size); bool readVPTR(Common::SeekableReadStream *s, uint32 size); @@ -157,6 +166,8 @@ private: protected: Common::Rational getFrameRate() const; + bool useAudioSync() const { return false; } + private: Graphics::Surface *_surface; bool _hasNewFrame; @@ -172,22 +183,21 @@ private: uint32 _maxCBFZSize; uint32 _maxZBUFChunkSize; - size_t _codebookSize; + uint32 _codebookSize; uint8 *_codebook; uint8 *_cbfz; uint8 *_zbufChunk; - size_t _vptrSize; + uint32 _vptrSize; uint8 *_vptr; int _curFrame; - void VPTRWriteBlock(uint16 *frame, unsigned int dstBlock, unsigned int srcBlock, int count, bool alpha = false); bool decodeFrame(uint16 *frame); }; - class VQAAudioTrack : public AudioTrack { + class VQAAudioTrack { public: VQAAudioTrack(VQADecoder *vqaDecoder); ~VQAAudioTrack(); @@ -195,33 +205,14 @@ private: bool readSND2(Common::SeekableReadStream *s, uint32 size); bool readSN2J(Common::SeekableReadStream *s, uint32 size); + Audio::SeekableAudioStream *decodeAudioFrame(); protected: - Audio::AudioStream *getAudioStream() const; private: - Audio::QueuingAudioStream *_audioStream; - + uint16 _frequency; ADPCMWestwoodDecoder _adpcmDecoder; uint8 _compressedAudioFrame[735]; }; - -/* - bool readFrame(); - - int getFrameTime() { return 1000 / _header.frameRate; } - - void VPTRWriteBlock(uint16 *frame, unsigned int dstBlock, unsigned int srcBlock, int count, bool alpha = false) const; - - bool seekToFrame(int frame); - bool decodeFrame(uint16 *frame); - - int16 *getAudioFrame(); - - // bool get_view(view_t *view); - bool getZBUF(uint16 *zbuf); - - friend class VQAPlayer; -*/ }; }; // End of namespace BladeRunner diff --git a/engines/bladerunner/vqa_player.cpp b/engines/bladerunner/vqa_player.cpp index f05e14ba44..4c83079730 100644 --- a/engines/bladerunner/vqa_player.cpp +++ b/engines/bladerunner/vqa_player.cpp @@ -35,91 +35,98 @@ bool VQAPlayer::open(const Common::String &name) { if (!_s) return false; - if(!_decoder.open(_s)) { + if(!_decoder.loadStream(_s)) { delete _s; _s = nullptr; return false; } - _audioStream = Audio::makeQueuingAudioStream(_decoder._header.freq, _decoder._header.channels == 2); + _audioStream = Audio::makeQueuingAudioStream(_decoder.frequency(), false); return true; } +void VQAPlayer::close() { + _vm->_mixer->stopHandle(_soundHandle); + delete[] _s; + _s = nullptr; +} + int VQAPlayer::update() { - uint32 now = _vm->_system->getMillis(); - - if (_nextFrameTime == 0) - _nextFrameTime = now; - - if (now < _nextFrameTime) - return -1; - - _nextFrameTime += 1000 / _decoder._header.frameRate; - - if (_decoder._loopInfo.loopCount) { - if (_loopSpecial >= 0) { - _curLoop = _loopSpecial; - _loopSpecial = -3; - - _curFrame = _decoder._loopInfo.loops[_curLoop].begin; - _decoder.seekToFrame(_curFrame); - } else if (_curLoop == -1 && _loopDefault >= 0) { - _curLoop = _loopDefault; - _curFrame = _decoder._loopInfo.loops[_curLoop].begin; - _decoder.seekToFrame(_curFrame); - } else if (_curLoop >= 0 && _curFrame == _decoder._loopInfo.loops[_curLoop].end) { - if (_loopDefault == -1) - return -3; - - _curLoop = _loopDefault; - _curFrame = _decoder._loopInfo.loops[_curLoop].begin; - _decoder.seekToFrame(_curFrame); + uint32 now = 60 * _vm->_system->getMillis(); + + if (_curFrame == -1) { + _curFrame = 0; + if (_curFrame >= 0) { + _decoder.readNextPacket(); + queueAudioFrame(_decoder.decodeAudioFrame()); + _surface = _decoder.decodeVideoFrame(); } - else - ++_curFrame; - } - else - ++_curFrame; - if (_curFrame >= _decoder._header.numFrames) { - if (_audioStream) - _audioStream->finish(); - return -3; - } + _decodedFrame = calcNextFrame(_curFrame); + if (_decodedFrame >= 0) { + _decoder.readNextPacket(); + queueAudioFrame(_decoder.decodeAudioFrame()); + } - _decoder.readFrame(); - _decoder.decodeFrame((uint16*)_surface->getPixels()); + _vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, _audioStream); + _audioStarted = true; - if (_audioStream) { - int16 *audioFrame = (int16*)malloc(2940); - memcpy(audioFrame, _decoder.getAudioFrame(), 2940); - _audioStream->queueBuffer((byte*)audioFrame, 2940, DisposeAfterUse::YES, Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN); + _nextFrameTime = now + 60000 / 15; + return _curFrame; + } - if (!_audioStarted) - _vm->_mixer->playStream( - Audio::Mixer::kPlainSoundType, - &_soundHandle, - _audioStream, - -1 - ); + if (now >= _nextFrameTime) { + _curFrame = _decodedFrame; + if (_curFrame >= 0) { + _surface = _decoder.decodeVideoFrame(); + } - _audioStarted = true; + _decodedFrame = calcNextFrame(_curFrame); + if (_decodedFrame >= 0) { + _decoder.readNextPacket(); + queueAudioFrame(_decoder.decodeAudioFrame()); + } + + _nextFrameTime += 60000 / 15; + return _curFrame; } - return _curFrame; + _surface = nullptr; + return -1; +} + +const Graphics::Surface *VQAPlayer::getSurface() const { + return _surface; } -void VQAPlayer::setLoopSpecial(int loop, bool wait) -{ +void VQAPlayer::setLoopSpecial(int loop, bool wait) { _loopSpecial = loop; if (!wait) _curLoop = -1; } -void VQAPlayer::setLoopDefault(int loop) -{ +void VQAPlayer::setLoopDefault(int loop) { _loopDefault = loop; } +int VQAPlayer::calcNextFrame(int frame) const { + if (frame < 0) + return -3; + + frame += 1; + + if (frame == _decoder.numFrames()) + frame = -3; + + return frame; +} + +void VQAPlayer::queueAudioFrame(Audio::AudioStream *audioStream) { + int n = _audioStream->numQueuedStreams(); + if (n == 0) + warning("numQueuedStreams: %d", n); + _audioStream->queueAudioStream(audioStream, DisposeAfterUse::YES); +} + }; // End of namespace BladeRunner diff --git a/engines/bladerunner/vqa_player.h b/engines/bladerunner/vqa_player.h index 7e7fab5b5f..e38a2748bd 100644 --- a/engines/bladerunner/vqa_player.h +++ b/engines/bladerunner/vqa_player.h @@ -38,10 +38,11 @@ class VQAPlayer { BladeRunnerEngine *_vm; Common::SeekableReadStream *_s; VQADecoder _decoder; - Graphics::Surface *_surface; + const Graphics::Surface *_surface; Audio::QueuingAudioStream *_audioStream; int _curFrame; + int _decodedFrame; int _curLoop; int _loopSpecial; int _loopDefault; @@ -52,12 +53,13 @@ class VQAPlayer { public: - VQAPlayer(BladeRunnerEngine *vm, Graphics::Surface *surface) + VQAPlayer(BladeRunnerEngine *vm) : _vm(vm), _s(nullptr), - _surface(surface), + _surface(nullptr), _audioStream(nullptr), _curFrame(-1), + _decodedFrame(-1), _curLoop(-1), _loopSpecial(-1), _loopDefault(-1), @@ -65,11 +67,22 @@ public: _audioStarted(false) {} + ~VQAPlayer() { + close(); + } + bool open(const Common::String &name); + void close(); + int update(); + const Graphics::Surface *getSurface() const; void setLoopSpecial(int loop, bool wait); void setLoopDefault(int loop); + +private: + int calcNextFrame(int frame) const; + void queueAudioFrame(Audio::AudioStream *audioStream); }; }; // End of namespace BladeRunner |