aboutsummaryrefslogtreecommitdiff
path: root/engines/bladerunner
diff options
context:
space:
mode:
authorThomas Fach-Pedersen2014-05-24 12:15:17 +0200
committerEugene Sandulenko2016-09-29 22:33:17 +0200
commit8217ed6065ac0c45edaeb672908da7e91a068c4f (patch)
tree482836c5bde6dcc83e09f9e4f2dbecdb5e7f12d5 /engines/bladerunner
parenta67e9e16bdbb5acbb2d1eb52a87c3eb2d128c44d (diff)
downloadscummvm-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/bladerunner')
-rw-r--r--engines/bladerunner/module.mk3
-rw-r--r--engines/bladerunner/outtake.cpp34
-rw-r--r--engines/bladerunner/vqa_decoder.cpp64
-rw-r--r--engines/bladerunner/vqa_decoder.h55
-rw-r--r--engines/bladerunner/vqa_player.cpp125
-rw-r--r--engines/bladerunner/vqa_player.h19
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