aboutsummaryrefslogtreecommitdiff
path: root/engines/bladerunner
diff options
context:
space:
mode:
authorThomas Fach-Pedersen2014-05-20 11:30:16 +0200
committerEugene Sandulenko2016-09-29 22:33:11 +0200
commita67e9e16bdbb5acbb2d1eb52a87c3eb2d128c44d (patch)
treeee7a8fc9e98d09228948869f312d04b9db367e43 /engines/bladerunner
parent5fd05a41d7908dd63420c91134965b7d14c4b3ae (diff)
downloadscummvm-rg350-a67e9e16bdbb5acbb2d1eb52a87c3eb2d128c44d.tar.gz
scummvm-rg350-a67e9e16bdbb5acbb2d1eb52a87c3eb2d128c44d.tar.bz2
scummvm-rg350-a67e9e16bdbb5acbb2d1eb52a87c3eb2d128c44d.zip
BLADERUNNER: Rebuild VQADecoder on top of Video::VideoDecoder
Diffstat (limited to 'engines/bladerunner')
-rw-r--r--engines/bladerunner/aud_decoder.cpp167
-rw-r--r--engines/bladerunner/aud_decoder.h50
-rw-r--r--engines/bladerunner/bladerunner.cpp15
-rw-r--r--engines/bladerunner/module.mk4
-rw-r--r--engines/bladerunner/outtake.cpp40
-rw-r--r--engines/bladerunner/outtake.h6
-rw-r--r--engines/bladerunner/vqa_decoder.cpp614
-rw-r--r--engines/bladerunner/vqa_decoder.h150
-rw-r--r--engines/bladerunner/vqa_player.cpp25
-rw-r--r--engines/bladerunner/vqa_player.h6
10 files changed, 723 insertions, 354 deletions
diff --git a/engines/bladerunner/aud_decoder.cpp b/engines/bladerunner/aud_decoder.cpp
new file mode 100644
index 0000000000..d11a90e196
--- /dev/null
+++ b/engines/bladerunner/aud_decoder.cpp
@@ -0,0 +1,167 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "bladerunner/aud_decoder.h"
+
+#include "common/util.h"
+
+namespace BladeRunner {
+
+static const
+int16 imaIndexTable[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };
+
+static const
+uint16 imaStepTable[712] =
+{
+ 0x0000,0x0001,0x0003,0x0004,0x0007,0x0008,0x000a,0x000b,
+ 0x0001,0x0003,0x0005,0x0007,0x0009,0x000b,0x000d,0x000f,
+ 0x0001,0x0003,0x0005,0x0007,0x000a,0x000c,0x000e,0x0010,
+ 0x0001,0x0003,0x0006,0x0008,0x000b,0x000d,0x0010,0x0012,
+ 0x0001,0x0003,0x0006,0x0008,0x000c,0x000e,0x0011,0x0013,
+ 0x0001,0x0004,0x0007,0x000a,0x000d,0x0010,0x0013,0x0016,
+ 0x0001,0x0004,0x0007,0x000a,0x000e,0x0011,0x0014,0x0017,
+ 0x0001,0x0004,0x0008,0x000b,0x000f,0x0012,0x0016,0x0019,
+ 0x0002,0x0006,0x000a,0x000e,0x0012,0x0016,0x001a,0x001e,
+ 0x0002,0x0006,0x000a,0x000e,0x0013,0x0017,0x001b,0x001f,
+ 0x0002,0x0006,0x000b,0x000f,0x0015,0x0019,0x001e,0x0022,
+ 0x0002,0x0007,0x000c,0x0011,0x0017,0x001c,0x0021,0x0026,
+ 0x0002,0x0007,0x000d,0x0012,0x0019,0x001e,0x0024,0x0029,
+ 0x0003,0x0009,0x000f,0x0015,0x001c,0x0022,0x0028,0x002e,
+ 0x0003,0x000a,0x0011,0x0018,0x001f,0x0026,0x002d,0x0034,
+ 0x0003,0x000a,0x0012,0x0019,0x0022,0x0029,0x0031,0x0038,
+ 0x0004,0x000c,0x0015,0x001d,0x0026,0x002e,0x0037,0x003f,
+ 0x0004,0x000d,0x0016,0x001f,0x0029,0x0032,0x003b,0x0044,
+ 0x0005,0x000f,0x0019,0x0023,0x002e,0x0038,0x0042,0x004c,
+ 0x0005,0x0010,0x001b,0x0026,0x0032,0x003d,0x0048,0x0053,
+ 0x0006,0x0012,0x001f,0x002b,0x0038,0x0044,0x0051,0x005d,
+ 0x0006,0x0013,0x0021,0x002e,0x003d,0x004a,0x0058,0x0065,
+ 0x0007,0x0016,0x0025,0x0034,0x0043,0x0052,0x0061,0x0070,
+ 0x0008,0x0018,0x0029,0x0039,0x004a,0x005a,0x006b,0x007b,
+ 0x0009,0x001b,0x002d,0x003f,0x0052,0x0064,0x0076,0x0088,
+ 0x000a,0x001e,0x0032,0x0046,0x005a,0x006e,0x0082,0x0096,
+ 0x000b,0x0021,0x0037,0x004d,0x0063,0x0079,0x008f,0x00a5,
+ 0x000c,0x0024,0x003c,0x0054,0x006d,0x0085,0x009d,0x00b5,
+ 0x000d,0x0027,0x0042,0x005c,0x0078,0x0092,0x00ad,0x00c7,
+ 0x000e,0x002b,0x0049,0x0066,0x0084,0x00a1,0x00bf,0x00dc,
+ 0x0010,0x0030,0x0051,0x0071,0x0092,0x00b2,0x00d3,0x00f3,
+ 0x0011,0x0034,0x0058,0x007b,0x00a0,0x00c3,0x00e7,0x010a,
+ 0x0013,0x003a,0x0061,0x0088,0x00b0,0x00d7,0x00fe,0x0125,
+ 0x0015,0x0040,0x006b,0x0096,0x00c2,0x00ed,0x0118,0x0143,
+ 0x0017,0x0046,0x0076,0x00a5,0x00d5,0x0104,0x0134,0x0163,
+ 0x001a,0x004e,0x0082,0x00b6,0x00eb,0x011f,0x0153,0x0187,
+ 0x001c,0x0055,0x008f,0x00c8,0x0102,0x013b,0x0175,0x01ae,
+ 0x001f,0x005e,0x009d,0x00dc,0x011c,0x015b,0x019a,0x01d9,
+ 0x0022,0x0067,0x00ad,0x00f2,0x0139,0x017e,0x01c4,0x0209,
+ 0x0026,0x0072,0x00bf,0x010b,0x0159,0x01a5,0x01f2,0x023e,
+ 0x002a,0x007e,0x00d2,0x0126,0x017b,0x01cf,0x0223,0x0277,
+ 0x002e,0x008a,0x00e7,0x0143,0x01a1,0x01fd,0x025a,0x02b6,
+ 0x0033,0x0099,0x00ff,0x0165,0x01cb,0x0231,0x0297,0x02fd,
+ 0x0038,0x00a8,0x0118,0x0188,0x01f9,0x0269,0x02d9,0x0349,
+ 0x003d,0x00b8,0x0134,0x01af,0x022b,0x02a6,0x0322,0x039d,
+ 0x0044,0x00cc,0x0154,0x01dc,0x0264,0x02ec,0x0374,0x03fc,
+ 0x004a,0x00df,0x0175,0x020a,0x02a0,0x0335,0x03cb,0x0460,
+ 0x0052,0x00f6,0x019b,0x023f,0x02e4,0x0388,0x042d,0x04d1,
+ 0x005a,0x010f,0x01c4,0x0279,0x032e,0x03e3,0x0498,0x054d,
+ 0x0063,0x012a,0x01f1,0x02b8,0x037f,0x0446,0x050d,0x05d4,
+ 0x006d,0x0148,0x0223,0x02fe,0x03d9,0x04b4,0x058f,0x066a,
+ 0x0078,0x0168,0x0259,0x0349,0x043b,0x052b,0x061c,0x070c,
+ 0x0084,0x018d,0x0296,0x039f,0x04a8,0x05b1,0x06ba,0x07c3,
+ 0x0091,0x01b4,0x02d8,0x03fb,0x051f,0x0642,0x0766,0x0889,
+ 0x00a0,0x01e0,0x0321,0x0461,0x05a2,0x06e2,0x0823,0x0963,
+ 0x00b0,0x0210,0x0371,0x04d1,0x0633,0x0793,0x08f4,0x0a54,
+ 0x00c2,0x0246,0x03ca,0x054e,0x06d2,0x0856,0x09da,0x0b5e,
+ 0x00d5,0x027f,0x042a,0x05d4,0x0780,0x092a,0x0ad5,0x0c7f,
+ 0x00ea,0x02bf,0x0495,0x066a,0x0840,0x0a15,0x0beb,0x0dc0,
+ 0x0102,0x0306,0x050b,0x070f,0x0914,0x0b18,0x0d1d,0x0f21,
+ 0x011c,0x0354,0x058c,0x07c4,0x09fc,0x0c34,0x0e6c,0x10a4,
+ 0x0138,0x03a8,0x0619,0x0889,0x0afb,0x0d6b,0x0fdc,0x124c,
+ 0x0157,0x0406,0x06b5,0x0964,0x0c14,0x0ec3,0x1172,0x1421,
+ 0x017a,0x046e,0x0762,0x0a56,0x0d4a,0x103e,0x1332,0x1626,
+ 0x019f,0x04de,0x081e,0x0b5d,0x0e9e,0x11dd,0x151d,0x185c,
+ 0x01c9,0x055c,0x08ef,0x0c82,0x1015,0x13a8,0x173b,0x1ace,
+ 0x01f7,0x05e5,0x09d4,0x0dc2,0x11b1,0x159f,0x198e,0x1d7c,
+ 0x0229,0x067c,0x0acf,0x0f22,0x1375,0x17c8,0x1c1b,0x206e,
+ 0x0260,0x0721,0x0be3,0x10a4,0x1567,0x1a28,0x1eea,0x23ab,
+ 0x029d,0x07d8,0x0d14,0x124f,0x178b,0x1cc6,0x2202,0x273d,
+ 0x02e0,0x08a1,0x0e63,0x1424,0x19e6,0x1fa7,0x2569,0x2b2a,
+ 0x032a,0x097f,0x0fd4,0x1629,0x1c7e,0x22d3,0x2928,0x2f7d,
+ 0x037b,0x0a72,0x1169,0x1860,0x1f57,0x264e,0x2d45,0x343c,
+ 0x03d4,0x0b7d,0x1326,0x1acf,0x2279,0x2a22,0x31cb,0x3974,
+ 0x0436,0x0ca3,0x1511,0x1d7e,0x25ec,0x2e59,0x36c7,0x3f34,
+ 0x04a2,0x0de7,0x172c,0x2071,0x29b7,0x32fc,0x3c41,0x4586,
+ 0x0519,0x0f4b,0x197e,0x23b0,0x2de3,0x3815,0x4248,0x4c7a,
+ 0x059b,0x10d2,0x1c0a,0x2741,0x327a,0x3db1,0x48e9,0x5420,
+ 0x062b,0x1281,0x1ed8,0x2b2e,0x3786,0x43dc,0x5033,0x5c89,
+ 0x06c9,0x145b,0x21ee,0x2f80,0x3d14,0x4aa6,0x5839,0x65cb,
+ 0x0777,0x1665,0x2553,0x3441,0x4330,0x521e,0x610c,0x6ffa,
+ 0x0836,0x18a2,0x290f,0x397b,0x49e8,0x5a54,0x6ac1,0x7b2d,
+ 0x0908,0x1b19,0x2d2a,0x3f3b,0x514c,0x635d,0x756e,0x877f,
+ 0x09ef,0x1dce,0x31ae,0x458d,0x596d,0x6d4c,0x812c,0x950b,
+ 0x0aee,0x20ca,0x36a6,0x4c82,0x625f,0x783b,0x8e17,0xa3f3,
+ 0x0c05,0x2410,0x3c1c,0x5427,0x6c34,0x843f,0x9c4b,0xb456,
+ 0x0d39,0x27ac,0x4220,0x5c93,0x7707,0x917a,0xabee,0xc661,
+ 0x0e8c,0x2ba4,0x48bd,0x65d5,0x82ee,0xa006,0xbd1f,0xda37,
+ 0x0fff,0x2ffe,0x4ffe,0x6ffd,0x8ffe,0xaffd,0xcffd,0xeffc
+};
+
+void ADPCMWestwoodDecoder::decode(uint8 *in, size_t size, int16 *out)
+{
+ uint8 *end = in + size;
+
+ int16 stepIndex = _stepIndex;
+ int32 predictor = _predictor;
+
+ while (in != end)
+ {
+ uint16 bl = *in++;
+
+ for (int n = 0; n != 2; ++n)
+ {
+ uint8 nibble = (bl >> (4 * n)) & 0x0f;
+ uint8 code = nibble & 0x07;
+ uint8 sign = nibble & 0x08;
+
+ int diff = imaStepTable[(stepIndex << 3) | code];
+
+ // Westwood's IMA ADPCM differs from the below standard implementation
+ // in the LSB in a couple of places.
+ //int diff = imaStepTable_std[stepIndex] * code / 4 + imaStepTable_std[stepIndex] / 8;
+
+ if (sign)
+ predictor -= diff;
+ else
+ predictor += diff;
+
+ predictor = CLIP<int32>(predictor, -32768, 32767);
+
+ *out++ = (int16)predictor;
+
+ stepIndex = imaIndexTable[code] + stepIndex;
+ stepIndex = CLIP<int16>(stepIndex, 0, 88);
+ }
+ }
+
+ _stepIndex = stepIndex;
+ _predictor = predictor;
+}
+
+};
diff --git a/engines/bladerunner/aud_decoder.h b/engines/bladerunner/aud_decoder.h
new file mode 100644
index 0000000000..dbf7ca1dfa
--- /dev/null
+++ b/engines/bladerunner/aud_decoder.h
@@ -0,0 +1,50 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef BLADERUNNER_AUD_DECODER_H
+#define BLADERUNNER_AUD_DECODER_H
+
+#include "common/types.h"
+
+namespace BladeRunner {
+
+class ADPCMWestwoodDecoder {
+ int16 _stepIndex;
+ int32 _predictor;
+
+public:
+ ADPCMWestwoodDecoder()
+ : _stepIndex(0), _predictor(0)
+ {}
+
+ void setParameters(int16 stepIndex, int32 predictor)
+ {
+ _stepIndex = stepIndex;
+ _predictor = predictor;
+ }
+
+ void decode(uint8 *in, size_t size, int16 *out);
+};
+
+};
+
+#endif
diff --git a/engines/bladerunner/bladerunner.cpp b/engines/bladerunner/bladerunner.cpp
index bcf8c090a8..e914f1c032 100644
--- a/engines/bladerunner/bladerunner.cpp
+++ b/engines/bladerunner/bladerunner.cpp
@@ -58,13 +58,12 @@ Common::Error BladeRunnerEngine::run() {
startup();
- if (!warnUserAboutUnsupportedGame())
- return Common::kNoError;
+ if (warnUserAboutUnsupportedGame()) {
+ init2();
- init2();
-
- /* TODO: Check for save games and enter KIA */
- gameLoop();
+ /* TODO: Check for save games and enter KIA */
+ gameLoop();
+ }
shutdown();
@@ -169,6 +168,10 @@ void BladeRunnerEngine::gameTick() {
// TODO: Only run if not in Kia, script, nor AI
_settings->openNewScene();
+ outtakePlay(28, true);
+ outtakePlay(41, true);
+ outtakePlay( 0, false);
+
// TODO: Autosave
// TODO: Kia
// TODO: Spinner
diff --git a/engines/bladerunner/module.mk b/engines/bladerunner/module.mk
index 44e681abf4..23113a9a60 100644
--- a/engines/bladerunner/module.mk
+++ b/engines/bladerunner/module.mk
@@ -2,6 +2,7 @@ MODULE := engines/bladerunner
MODULE_OBJS = \
archive.o \
+ aud_decoder.o \
bladerunner.o \
chapters.o \
decompress_lcw.o \
@@ -11,8 +12,7 @@ MODULE_OBJS = \
image.o \
outtake.o \
settings.o \
- vqa_decoder.o \
- vqa_player.o
+ vqa_decoder.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 01ceefad75..6ebede5663 100644
--- a/engines/bladerunner/outtake.cpp
+++ b/engines/bladerunner/outtake.cpp
@@ -23,8 +23,10 @@
#include "bladerunner/outtake.h"
#include "bladerunner/bladerunner.h"
-#include "bladerunner/vqa_player.h"
+#include "bladerunner/vqa_decoder.h"
+#include "common/debug.h"
+#include "common/events.h"
#include "common/system.h"
namespace BladeRunner {
@@ -41,27 +43,33 @@ void OuttakePlayer::play(const Common::String &name, bool noLocalization, int co
else
resName = name + "_E.VQA";
- _vqaPlayer = new VQAPlayer(_vm, &_vm->_surface1);
- _vqaPlayer->open(resName);
+ Common::SeekableReadStream *s = _vm->getResourceStream(resName);
- for (;;) {
- _vm->handleEvents();
- if (_vm->shouldQuit())
- break;
+ _vqaDecoder = new VQADecoder();
+ _vqaDecoder->loadStream(s);
- int r = _vqaPlayer->update();
- if (r == -3)
- break;
+ _vqaDecoder->start();
- if (r >= 0) {
- _vm->_system->copyRectToScreen(_vm->_surface1.getPixels(), _vm->_surface1.pitch, 0, 0, _vm->_surface1.w, _vm->_surface1.h);
+ uint32 last = _vm->_system->getMillis();
+
+ while (!_vqaDecoder->endOfVideo() && !_vm->shouldQuit()) {
+ if (_vqaDecoder->needsUpdate()) {
+ uint32 now = _vm->_system->getMillis();
+ debug("delta: %d", now - last);
+ last = now;
+
+ const Graphics::Surface *surface = _vqaDecoder->decodeNextFrame();
+ _vm->_system->copyRectToScreen((const byte *)surface->getBasePtr(0, 0), surface->pitch, 0, 0, 640, 480);
_vm->_system->updateScreen();
- _vm->_system->delayMillis(10);
}
- }
- delete _vqaPlayer;
- _vqaPlayer = nullptr;
+ 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);
+ }
}
}; // End of namespace BladeRunner
diff --git a/engines/bladerunner/outtake.h b/engines/bladerunner/outtake.h
index 4e97b1b516..9182b878c0 100644
--- a/engines/bladerunner/outtake.h
+++ b/engines/bladerunner/outtake.h
@@ -30,20 +30,20 @@
namespace BladeRunner {
class BladeRunnerEngine;
-class VQAPlayer;
+class VQADecoder;
class OuttakePlayer {
BladeRunnerEngine *_vm;
bool _isVQAOpen;
- VQAPlayer *_vqaPlayer;
+ VQADecoder *_vqaDecoder;
Graphics::Surface *_surface;
public:
OuttakePlayer(BladeRunnerEngine *vm) :
_vm(vm),
_isVQAOpen(false),
- _vqaPlayer(nullptr)
+ _vqaDecoder(nullptr)
{}
void play(const Common::String &name, bool noLocalization, int container);
diff --git a/engines/bladerunner/vqa_decoder.cpp b/engines/bladerunner/vqa_decoder.cpp
index f4676d39d6..bd898bc171 100644
--- a/engines/bladerunner/vqa_decoder.cpp
+++ b/engines/bladerunner/vqa_decoder.cpp
@@ -22,9 +22,12 @@
#include "bladerunner/vqa_decoder.h"
+#include "bladerunner/bladerunner.h"
#include "bladerunner/decompress_lcw.h"
#include "bladerunner/decompress_lzo.h"
+#include "audio/decoders/raw.h"
+
#include "common/array.h"
#include "common/util.h"
@@ -63,23 +66,14 @@ namespace BladeRunner {
#define kWVQA 0x57565141
#define kZBUF 0x5A425546
-VQADecoder::VQADecoder()
- : _s(nullptr),
- _frame(0),
- _zbuf(0),
- _codebook(0),
- _cbfz(0),
- _vptr(0),
- _hasView(false),
- _audioFrame(0),
- _maxVIEWChunkSize(0),
- _maxZBUFChunkSize(0),
- _maxAESCChunkSize(0)
-{
-}
+int32 remain(Common::SeekableReadStream *s) {
+ int32 pos = s->pos();
+ if (pos == -1) return -1;
-VQADecoder::~VQADecoder()
-{
+ int32 size = s->size();
+ if (size == -1) return -1;
+
+ return size - pos;
}
struct IFFChunkHeader
@@ -92,23 +86,6 @@ struct IFFChunkHeader
uint32 size;
};
-static inline uint32 roundup(uint32 v)
-{
- return (v + 1) & ~1u;
-}
-
-const char *strTag(uint32 tag);
-
-int32 remain(Common::SeekableReadStream *s) {
- int32 pos = s->pos();
- if (pos == -1) return -1;
-
- int32 size = s->size();
- if (size == -1) return -1;
-
- return size - pos;
-}
-
static
bool readIFFChunkHeader(Common::SeekableReadStream *s, IFFChunkHeader *ts)
{
@@ -118,12 +95,14 @@ bool readIFFChunkHeader(Common::SeekableReadStream *s, IFFChunkHeader *ts)
ts->id = s->readUint32BE();
ts->size = s->readUint32BE();
- // if (ts->size != roundup(ts->size))
- // debug("%s: %d", strTag(ts->id), ts->size);
-
return true;
}
+static inline uint32 roundup(uint32 v)
+{
+ return (v + 1) & ~1u;
+}
+
const char *strTag(uint32 tag)
{
static char s[5];
@@ -137,8 +116,21 @@ const char *strTag(uint32 tag)
return s;
}
-bool VQADecoder::open(Common::SeekableReadStream *s)
+VQADecoder::VQADecoder()
+ : _s(nullptr),
+ _maxVIEWChunkSize(0),
+ _maxZBUFChunkSize(0),
+ _maxAESCChunkSize(0)
{
+}
+
+VQADecoder::~VQADecoder() {
+}
+
+bool VQADecoder::loadStream(Common::SeekableReadStream *s) {
+ close();
+ _s = s;
+
IFFChunkHeader chd;
uint32 type;
bool rc;
@@ -152,81 +144,124 @@ bool VQADecoder::open(Common::SeekableReadStream *s)
if (type != kWVQA)
return false;
- _s = s;
do {
if (!readIFFChunkHeader(_s, &chd))
return false;
- debug("\t%s : %x", strTag(chd.id), chd.size);
-
rc = false;
switch (chd.id)
{
- case kCINF: rc = readCINF(chd.size); break;
- case kCLIP: rc = readCLIP(chd.size); break;
- case kFINF: rc = readFINF(chd.size); break;
- case kLINF: rc = readLINF(chd.size); break;
- case kLNIN: rc = readLNIN(chd.size); break;
- case kMFCI: rc = readMFCI(chd.size); break;
- case kMSCI: rc = readMSCI(chd.size); break;
- case kVQHD: rc = readVQHD(chd.size); break;
+ case kCINF: rc = readCINF(s, chd.size); break;
+ case kCLIP: rc = readCLIP(s, chd.size); break;
+ case kFINF: rc = readFINF(s, chd.size); break;
+ case kLINF: rc = readLINF(s, chd.size); break;
+ case kLNIN: rc = readLNIN(s, chd.size); break;
+ case kMFCI: rc = readMFCI(s, chd.size); break;
+ case kMSCI: rc = readMSCI(s, chd.size); break;
+ case kVQHD: rc = readVQHD(s, chd.size); break;
default:
debug("Unhandled chunk '%s'", strTag(chd.id));
- _s->skip(roundup(chd.size));
+ s->skip(roundup(chd.size));
rc = true;
}
- if (!rc)
- {
+ if (!rc) {
debug("failed to handle chunk %s", strTag(chd.id));
- return -1;
+ return false;
}
-
} while (chd.id != kFINF);
+ _videoTrack = new VQAVideoTrack(this);
+ addTrack(_videoTrack);
+
+ _audioTrack = new VQAAudioTrack(this);
+ addTrack(_audioTrack);
+
+ /*
for (int i = 0; i != _loopInfo.loopCount; ++i) {
debug("LOOP %2d: %4d %4d %s", i,
_loopInfo.loops[i].begin,
_loopInfo.loops[i].end,
_loopInfo.loops[i].name.c_str());
}
+ */
return true;
}
-bool VQADecoder::readVQHD(uint32 size)
+void VQADecoder::readNextPacket() {
+ IFFChunkHeader chd;
+
+ if (remain(_s) < 8) {
+ warning("remain: %d", remain(_s));
+ assert(remain(_s) < 8);
+ }
+
+ do {
+ if (!readIFFChunkHeader(_s, &chd)) {
+ warning("Error reading chunk header");
+ return;
+ }
+
+ bool rc = false;
+ switch (chd.id) {
+ // Video track
+ case kAESC: rc = _videoTrack->readAESC(_s, chd.size); break;
+ case kLITE: rc = _videoTrack->readLITE(_s, chd.size); break;
+ case kVIEW: rc = _videoTrack->readVIEW(_s, chd.size); break;
+ case kVQFL: rc = _videoTrack->readVQFL(_s, chd.size); break;
+ case kVQFR: rc = _videoTrack->readVQFR(_s, chd.size); break;
+ case kZBUF: rc = _videoTrack->readZBUF(_s, chd.size); break;
+ // Sound track
+ case kSN2J: rc = _audioTrack->readSN2J(_s, chd.size); break;
+ case kSND2: rc = _audioTrack->readSND2(_s, chd.size); break;
+
+ default:
+ _s->skip(roundup(chd.size));
+ rc = false;
+ }
+
+ if (!rc) {
+ warning("Error handling chunk %s", strTag(chd.id));
+ return;
+ }
+ } while (chd.id != kVQFR);
+}
+
+bool VQADecoder::readVQHD(Common::SeekableReadStream *s, uint32 size)
{
if (size != 42)
return false;
- _header.version = _s->readUint16LE();
- _header.flags = _s->readUint16LE();
- _header.numFrames = _s->readUint16LE();
- _header.width = _s->readUint16LE();
- _header.height = _s->readUint16LE();
- _header.blockW = _s->readByte();
- _header.blockH = _s->readByte();
- _header.frameRate = _s->readByte();
- _header.cbParts = _s->readByte();
- _header.colors = _s->readUint16LE();
- _header.maxBlocks = _s->readUint16LE();
- _header.offset_x = _s->readUint16LE();
- _header.offset_y = _s->readUint16LE();
- _header.maxVPTRSize = _s->readUint16LE();
- _header.freq = _s->readUint16LE();
- _header.channels = _s->readByte();
- _header.bits = _s->readByte();
- _header.unk3 = _s->readUint32LE();
- _header.unk4 = _s->readUint16LE();
- _header.maxCBFZSize = _s->readUint32LE();
- _header.unk5 = _s->readUint32LE();
-
- if (_header.offset_x || _header.offset_y)
+ _header.version = s->readUint16LE();
+ _header.flags = s->readUint16LE();
+ _header.numFrames = s->readUint16LE();
+ _header.width = s->readUint16LE();
+ _header.height = s->readUint16LE();
+ _header.blockW = s->readByte();
+ _header.blockH = s->readByte();
+ _header.frameRate = s->readByte();
+ _header.cbParts = s->readByte();
+ _header.colors = s->readUint16LE();
+ _header.maxBlocks = s->readUint16LE();
+ _header.offsetX = s->readUint16LE();
+ _header.offsetY = s->readUint16LE();
+ _header.maxVPTRSize = s->readUint16LE();
+ _header.freq = s->readUint16LE();
+ _header.channels = s->readByte();
+ _header.bits = s->readByte();
+ _header.unk3 = s->readUint32LE();
+ _header.unk4 = s->readUint16LE();
+ _header.maxCBFZSize = s->readUint32LE();
+ _header.unk5 = s->readUint32LE();
+
+ if (_header.offsetX || _header.offsetY)
{
- debug("_header.offset_x, _header.offset_y: %d %d", _header.offset_x, _header.offset_y);
+ 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);
debug("_header.flags %04x", _header.flags);
@@ -239,8 +274,8 @@ bool VQADecoder::readVQHD(uint32 size)
debug("_header.cbParts %d", _header.cbParts);
debug("_header.colors %d", _header.colors);
debug("_header.maxBlocks %d", _header.maxBlocks);
- debug("_header.offsetX %d", _header.offset_x);
- debug("_header.offsetY %d", _header.offset_y);
+ debug("_header.offsetX %d", _header.offsetX);
+ debug("_header.offsetY %d", _header.offsetY);
debug("_header.maxVPTRSize %d", _header.maxVPTRSize);
debug("_header.freq %d", _header.freq);
debug("_header.channels %d", _header.channels);
@@ -251,12 +286,39 @@ bool VQADecoder::readVQHD(uint32 size)
debug("_header.unk5 %d", _header.unk5);
}
- // exit(-1);
+ return true;
+}
+
+bool VQADecoder::VQAVideoTrack::readVQFR(Common::SeekableReadStream *s, uint32 size)
+{
+ IFFChunkHeader chd;
+
+ while (size >= 8)
+ {
+ if (!readIFFChunkHeader(s, &chd))
+ return false;
+ size -= roundup(chd.size) + 8;
+
+ bool rc = false;
+ switch (chd.id)
+ {
+ case kCBFZ: rc = readCBFZ(s, chd.size); break;
+ case kVPTR: rc = readVPTR(s, chd.size); break;
+ default:
+ s->skip(roundup(chd.size));
+ }
+
+ if (!rc)
+ {
+ debug("VQFR: error handling chunk %s", strTag(chd.id));
+ return false;
+ }
+ }
return true;
}
-bool VQADecoder::readMSCI(uint32 size)
+bool VQADecoder::readMSCI(Common::SeekableReadStream *s, uint32 size)
{
IFFChunkHeader chd;
readIFFChunkHeader(_s, &chd);
@@ -265,8 +327,8 @@ bool VQADecoder::readMSCI(uint32 size)
return false;
uint32 count, unk0;
- count = _s->readUint32LE();
- unk0 = _s->readUint32LE();
+ count = s->readUint32LE();
+ unk0 = s->readUint32LE();
assert(unk0 == 0);
readIFFChunkHeader(_s, &chd);
@@ -276,8 +338,8 @@ bool VQADecoder::readMSCI(uint32 size)
for (uint32 i = 0; i < count; ++i)
{
uint32 tag, size;
- tag = _s->readUint32BE();
- size = _s->readUint32LE();
+ tag = s->readUint32BE();
+ size = s->readUint32LE();
switch (tag)
{
@@ -287,7 +349,6 @@ bool VQADecoder::readMSCI(uint32 size)
break;
case kZBUF:
_maxZBUFChunkSize = size;
- _zbufChunk = new uint8[roundup(_maxZBUFChunkSize)];
debug("max ZBUF size: %08x", _maxZBUFChunkSize);
break;
case kAESC:
@@ -299,14 +360,14 @@ bool VQADecoder::readMSCI(uint32 size)
}
uint32 zero;
- zero = _s->readUint32LE(); assert(zero == 0);
- zero = _s->readUint32LE(); assert(zero == 0);
+ zero = s->readUint32LE(); assert(zero == 0);
+ zero = s->readUint32LE(); assert(zero == 0);
}
return true;
}
-bool VQADecoder::readLINF(uint32 size)
+bool VQADecoder::readLINF(Common::SeekableReadStream *s, uint32 size)
{
IFFChunkHeader chd;
readIFFChunkHeader(_s, &chd);
@@ -314,8 +375,8 @@ bool VQADecoder::readLINF(uint32 size)
if (chd.id != kLINH || chd.size != 6)
return false;
- _loopInfo.loopCount = _s->readUint16LE();
- _loopInfo.flags = _s->readUint32LE();
+ _loopInfo.loopCount = s->readUint16LE();
+ _loopInfo.flags = s->readUint32LE();
if ((_loopInfo.flags & 3) == 0)
return false;
@@ -327,8 +388,8 @@ bool VQADecoder::readLINF(uint32 size)
_loopInfo.loops = new Loop[_loopInfo.loopCount];
for (int i = 0; i != _loopInfo.loopCount; ++i)
{
- _loopInfo.loops[i].begin = _s->readUint16LE();
- _loopInfo.loops[i].end = _s->readUint16LE();
+ _loopInfo.loops[i].begin = s->readUint16LE();
+ _loopInfo.loops[i].end = s->readUint16LE();
// debug("Loop %d: %04x %04x", i, _loopInfo.loops[i].begin, _loopInfo.loops[i].end);
}
@@ -336,7 +397,7 @@ bool VQADecoder::readLINF(uint32 size)
return true;
}
-bool VQADecoder::readCINF(uint32 size)
+bool VQADecoder::readCINF(Common::SeekableReadStream *s, uint32 size)
{
IFFChunkHeader chd;
@@ -344,8 +405,8 @@ bool VQADecoder::readCINF(uint32 size)
if (chd.id != kCINH || chd.size != 8u)
return false;
- _clipInfo.clipCount = _s->readUint16LE();
- _s->skip(6);
+ _clipInfo.clipCount = s->readUint16LE();
+ s->skip(6);
readIFFChunkHeader(_s, &chd);
if (chd.id != kCIND || chd.size != 6u * _clipInfo.clipCount)
@@ -355,15 +416,14 @@ bool VQADecoder::readCINF(uint32 size)
{
uint16 a;
uint32 b;
- a = _s->readUint16LE();
- b = _s->readUint32LE();
- debug("%4d %08x", a, b);
+ a = s->readUint16LE();
+ b = s->readUint32LE();
}
return true;
}
-bool VQADecoder::readFINF(uint32 size)
+bool VQADecoder::readFINF(Common::SeekableReadStream *s, uint32 size)
{
if (size != 4u * _header.numFrames)
return false;
@@ -371,7 +431,7 @@ bool VQADecoder::readFINF(uint32 size)
_frameInfo = new uint32[_header.numFrames];
for (uint32 i = 0; i != _header.numFrames; ++i)
- _frameInfo[i] = _s->readUint32LE();
+ _frameInfo[i] = s->readUint32LE();
if (false) {
uint32 last = 0;
@@ -386,7 +446,7 @@ bool VQADecoder::readFINF(uint32 size)
return true;
}
-bool VQADecoder::readLNIN(uint32 size)
+bool VQADecoder::readLNIN(Common::SeekableReadStream *s, uint32 size)
{
IFFChunkHeader chd;
@@ -396,11 +456,11 @@ bool VQADecoder::readLNIN(uint32 size)
uint16 loopNamesCount, loopUnk1, loopUnk2, loopUnk3, loopUnk4;
- loopNamesCount = _s->readUint16LE();
- loopUnk1 = _s->readUint16LE();
- loopUnk2 = _s->readUint16LE();
- loopUnk3 = _s->readUint16LE();
- loopUnk4 = _s->readUint16LE();
+ loopNamesCount = s->readUint16LE();
+ loopUnk1 = s->readUint16LE();
+ loopUnk2 = s->readUint16LE();
+ loopUnk3 = s->readUint16LE();
+ loopUnk4 = s->readUint16LE();
if (loopNamesCount != _loopInfo.loopCount)
return false;
@@ -411,7 +471,7 @@ bool VQADecoder::readLNIN(uint32 size)
uint32 *loopNameOffsets = (uint32*)alloca(loopNamesCount * sizeof(uint32));
for (int i = 0; i != loopNamesCount; ++i) {
- loopNameOffsets[i] = _s->readUint32LE();
+ loopNameOffsets[i] = s->readUint32LE();
}
readIFFChunkHeader(_s, &chd);
@@ -419,7 +479,7 @@ bool VQADecoder::readLNIN(uint32 size)
return false;
char *names = (char*)alloca(roundup(chd.size));
- _s->read(names, roundup(chd.size));
+ s->read(names, roundup(chd.size));
for (int i = 0; i != loopNamesCount; ++i) {
char *begin = names + loopNameOffsets[i];
@@ -431,157 +491,113 @@ bool VQADecoder::readLNIN(uint32 size)
return true;
}
-bool VQADecoder::readCLIP(uint32 size)
-{
- _s->skip(roundup(size));
+bool VQADecoder::readCLIP(Common::SeekableReadStream *s, uint32 size) {
+ s->skip(roundup(size));
return true;
}
-bool VQADecoder::readMFCI(uint32 size)
-{
- _s->skip(roundup(size));
+bool VQADecoder::readMFCI(Common::SeekableReadStream *s, uint32 size) {
+ s->skip(roundup(size));
return true;
}
-bool VQADecoder::readFrame()
-{
- IFFChunkHeader chd;
-
- if (!_s)
- return false;
-
- _hasView = false;
+VQADecoder::VQAVideoTrack::VQAVideoTrack(VQADecoder *vqaDecoder) {
+ VQADecoder::Header *header = &vqaDecoder->_header;
- if (remain(_s) < 8) {
- debug("remain: %d", remain(_s));
- return false;
- }
+ _surface = nullptr;
+ _hasNewFrame = false;
- do {
- if (!readIFFChunkHeader(_s, &chd)) {
- debug("Error reading chunk header");
- return false;
- }
+ _numFrames = header->numFrames;
+ _width = header->width;
+ _height = header->height;
+ _blockW = header->blockW;
+ _blockH = header->blockH;
+ _frameRate = header->frameRate;
+ _maxBlocks = header->maxBlocks;
+ _offsetX = header->offsetX;
+ _offsetY = header->offsetY;
- // debug("%s ", strTag(chd.id));
+ _maxVPTRSize = header->maxVPTRSize;
+ _maxCBFZSize = header->maxCBFZSize;
+ _maxZBUFChunkSize = vqaDecoder->_maxZBUFChunkSize;
- bool rc = false;
- switch (chd.id)
- {
- case kAESC: rc = readAESC(chd.size); break;
- case kLITE: rc = readLITE(chd.size); break;
- case kSN2J: rc = readSN2J(chd.size); break;
- case kSND2: rc = readSND2(chd.size); break;
- case kVIEW: rc = readVIEW(chd.size); break;
- case kVQFL: rc = readVQFL(chd.size); break;
- case kVQFR: rc = readVQFR(chd.size); break;
- case kZBUF: rc = readZBUF(chd.size); break;
- default:
- _s->skip(roundup(chd.size));
- rc = true;
- }
+ _codebookSize = 0;
+ _codebook = nullptr;
+ _cbfz = nullptr;
+ _zbufChunk = nullptr;
- if (!rc)
- {
- debug("Error handling chunk %s", strTag(chd.id));
- return false;
- }
- } while (chd.id != kVQFR);
-
- return true;
-}
-
-
-bool VQADecoder::readSN2J(uint32 size)
-{
- if (size != 6)
- return false;
+ _vptrSize = 0;
+ _vptr = nullptr;
- uint16 step_index;
- uint32 predictor;
+ _curFrame = -1;
- step_index = _s->readUint16LE();
- predictor = _s->readUint32LE();
- // ima_adpcm_ws_decoder.set_parameters(step_index >> 5, predictor);
+ _zbufChunk = new uint8[roundup(_maxZBUFChunkSize)];
- return true;
+ _surface = new Graphics::Surface();
+ _surface->create(_width, _height, RGB555);
}
-bool VQADecoder::readSND2(uint32 size)
-{
- if (size != 735)
- {
- debug("audio frame size: %d", size);
- return false;
- }
-
- if (!_audioFrame)
- _audioFrame = new int16[2 * size];
- memset(_audioFrame, 0, 4 * size);
-
- uint8 *inFrame = new uint8[roundup(size)];
- _s->read(inFrame, roundup(size));
+VQADecoder::VQAVideoTrack::~VQAVideoTrack() {
+ delete[] _codebook;
+ delete[] _cbfz;
+ delete[] _zbufChunk;
+ delete[] _vptr;
- // ima_adpcm_ws_decoder.decode(inFrame, size, _audioFrame);
+ delete _surface;
+}
- delete[] inFrame;
+uint16 VQADecoder::VQAVideoTrack::getWidth() const {
+ return _width;
+}
- return true;
+uint16 VQADecoder::VQAVideoTrack::getHeight() const {
+ return _height;
}
-bool VQADecoder::readVQFR(uint32 size)
-{
- IFFChunkHeader chd;
+Graphics::PixelFormat VQADecoder::VQAVideoTrack::getPixelFormat() const {
+ return _surface->format;
+}
- while (size >= 8)
- {
- if (!readIFFChunkHeader(_s, &chd))
- return false;
- size -= roundup(chd.size) + 8;
+int VQADecoder::VQAVideoTrack::getCurFrame() const {
+ return _curFrame;
+}
- // debug("(%s) ", strTag(chd.id)); fflush(0);
+int VQADecoder::VQAVideoTrack::getFrameCount() const {
+ return _numFrames;
+}
- bool rc = false;
- switch (chd.id)
- {
- case kCBFZ: rc = readCBFZ(chd.size); break;
- case kVPTR: rc = readVPTR(chd.size); break;
- default:
- _s->skip(roundup(chd.size));
- }
+Common::Rational VQADecoder::VQAVideoTrack::getFrameRate() const {
+ return _frameRate;
+}
- if (!rc)
- {
- debug("VQFR: error handling chunk %s", strTag(chd.id));
- return false;
- }
+const Graphics::Surface *VQADecoder::VQAVideoTrack::decodeNextFrame() {
+ debug("_curFrame: %d", _curFrame);
+ if (_hasNewFrame) {
+ decodeFrame((uint16*)_surface->getPixels());
+ _curFrame++;
+ _hasNewFrame = false;
}
-
- return true;
+ return _surface;
}
-bool VQADecoder::readVQFL(uint32 size)
-{
+bool VQADecoder::VQAVideoTrack::readVQFL(Common::SeekableReadStream *s, uint32 size) {
IFFChunkHeader chd;
- while (size >= 8)
- {
- if (!readIFFChunkHeader(_s, &chd))
+ while (size >= 8) {
+ if (!readIFFChunkHeader(s, &chd))
return false;
size -= roundup(chd.size) + 8;
bool rc = false;
- switch (chd.id)
- {
- case kCBFZ: rc = readCBFZ(chd.size); break;
+ switch (chd.id) {
+ case kCBFZ: rc = readCBFZ(s, chd.size); break;
default:
- _s->skip(roundup(chd.size));
+ s->skip(roundup(chd.size));
}
- if (!rc)
- {
- debug("VQFL: error handling chunk %s", strTag(chd.id));
+ if (!rc) {
+ warning("VQFL: error handling chunk %s", strTag(chd.id));
return false;
}
}
@@ -589,29 +605,27 @@ bool VQADecoder::readVQFL(uint32 size)
return true;
}
-bool VQADecoder::readCBFZ(uint32 size)
-{
- if (size > _header.maxCBFZSize)
- {
- debug("%d > %d", size, _header.maxCBFZSize);
+bool VQADecoder::VQAVideoTrack::readCBFZ(Common::SeekableReadStream *s, uint32 size) {
+ if (size > _maxCBFZSize) {
+ debug("%d > %d", size, _maxCBFZSize);
return false;
}
- if (!_codebook)
- {
- _codebookSize = 2 * _header.maxBlocks * _header.blockW * _header.blockH;
+ if (!_codebook) {
+ _codebookSize = 2 * _maxBlocks * _blockW * _blockH;
_codebook = new uint8[_codebookSize];
}
if (!_cbfz)
- _cbfz = new uint8[roundup(_header.maxCBFZSize)];
+ _cbfz = new uint8[roundup(_maxCBFZSize)];
- _s->read(_cbfz, roundup(size));
+ s->read(_cbfz, roundup(size));
decompress_lcw(_cbfz, size, _codebook, _codebookSize);
return true;
}
+#if 0
static
int decodeZBUF_partial(uint8 *src, uint16 *curZBUF, uint32 srcLen)
{
@@ -655,52 +669,58 @@ int decodeZBUF_partial(uint8 *src, uint16 *curZBUF, uint32 srcLen)
}
return dstSize - dstRemain;
}
+#endif
-bool VQADecoder::readZBUF(uint32 size)
+bool VQADecoder::VQAVideoTrack::readZBUF(Common::SeekableReadStream *s, uint32 size)
{
+ s->skip(roundup(size));
+ return true;
+#if 0
if (size > _maxZBUFChunkSize) {
debug("VQA ERROR: ZBUF chunk size: %08x > %08x", size, _maxZBUFChunkSize);
- _s->skip(roundup(size));
+ s->skip(roundup(size));
return false;
}
uint32 width, height, complete, unk0;
- width = _s->readUint32LE();
- height = _s->readUint32LE();
- complete = _s->readUint32LE();
- unk0 = _s->readUint32LE();
+ width = s->readUint32LE();
+ height = s->readUint32LE();
+ complete = s->readUint32LE();
+ unk0 = s->readUint32LE();
uint32 remain = size - 16;
- if (width != _header.width || height != _header.height)
+ if (width != width || height != height)
{
debug("%d, %d, %d, %d", width, height, complete, unk0);
- _s->skip(roundup(remain));
+ s->skip(roundup(remain));
return false;
}
+ s->read(_zbufChunk, roundup(remain));
+
if (!_zbuf)
{
if (!complete) {
- _s->skip(roundup(remain));
+ s->skip(roundup(remain));
return false;
}
_zbuf = new uint16[width * height];
}
- _s->read(_zbufChunk, roundup(remain));
-
if (complete) {
size_t zbufOutSize;
decompress_lzo1x(_zbufChunk, remain, (uint8*)_zbuf, &zbufOutSize);
} else {
decodeZBUF_partial(_zbufChunk, _zbuf, remain);
}
+#endif
return true;
}
-bool VQADecoder::getZBUF(uint16 *zbuf)
+#if 0
+bool VQADecoder::VQAVideoTrack::getZBUF(uint16 *zbuf)
{
if (!_zbuf)
return false;
@@ -708,50 +728,51 @@ bool VQADecoder::getZBUF(uint16 *zbuf)
memcpy(zbuf, _zbuf, 2 * _header.width * _header.height);
return true;
}
+#endif
-bool VQADecoder::readVIEW(uint32 size)
+bool VQADecoder::VQAVideoTrack::readVIEW(Common::SeekableReadStream *s, uint32 size)
{
if (size != 56)
return false;
- _s->skip(size);
- // _hasView = true;
-
+ s->skip(size);
return true;
}
-bool VQADecoder::readAESC(uint32 size)
+bool VQADecoder::VQAVideoTrack::readAESC(Common::SeekableReadStream *s, uint32 size)
{
- _s->skip(roundup(size));
+ s->skip(roundup(size));
return true;
}
-bool VQADecoder::readLITE(uint32 size)
+bool VQADecoder::VQAVideoTrack::readLITE(Common::SeekableReadStream *s, uint32 size)
{
- _s->skip(roundup(size));
+ s->skip(roundup(size));
return true;
}
-bool VQADecoder::readVPTR(uint32 size)
+bool VQADecoder::VQAVideoTrack::readVPTR(Common::SeekableReadStream *s, uint32 size)
{
- if (size > _header.maxVPTRSize)
+ if (size > _maxVPTRSize)
return false;
if (!_vptr)
- _vptr = new uint8[roundup(_header.maxVPTRSize)];
+ _vptr = new uint8[roundup(_maxVPTRSize)];
_vptrSize = size;
- _s->read(_vptr, roundup(size));
+ s->read(_vptr, roundup(size));
+
+ _hasNewFrame = true;
return true;
}
-void VQADecoder::VPTRWriteBlock(uint16 *frame, unsigned int dstBlock, unsigned int srcBlock, int count, bool alpha) const
+void VQADecoder::VQAVideoTrack::VPTRWriteBlock(uint16 *frame, unsigned int dstBlock, unsigned int srcBlock, int count, bool alpha)
{
- uint16 frame_width = _header.width;
+ uint16 frame_width = _width;
uint32 frame_stride = 640;
- uint16 block_width = _header.blockW;
- uint16 block_height = _header.blockH;
+ uint16 block_width = _blockW;
+ uint16 block_height = _blockH;
const uint8 *const block_src =
&_codebook[2 * srcBlock * block_width * block_height];
@@ -760,8 +781,8 @@ void VQADecoder::VPTRWriteBlock(uint16 *frame, unsigned int dstBlock, unsigned i
do
{
- uint32 frame_x = dstBlock % blocks_per_line * block_width + _header.offset_x / 2;
- uint32 frame_y = dstBlock / blocks_per_line * block_height + _header.offset_y;
+ uint32 frame_x = dstBlock % blocks_per_line * block_width + _offsetX / 2;
+ uint32 frame_y = dstBlock / blocks_per_line * block_height + _offsetY;
uint32 dst_offset = frame_x + frame_y * frame_stride;
@@ -789,23 +810,11 @@ void VQADecoder::VPTRWriteBlock(uint16 *frame, unsigned int dstBlock, unsigned i
while (--count);
}
-bool VQADecoder::seekToFrame(int frame)
-{
- if (frame < 0 || frame >= _header.numFrames)
- return false;
-
- _s->seek(2 * (_frameInfo[frame] & 0x0fffffff), SEEK_SET);
- return true;
-}
-
-bool VQADecoder::decodeFrame(uint16 *frame)
+bool VQADecoder::VQAVideoTrack::decodeFrame(uint16 *frame)
{
if (!_codebook || !_vptr)
return false;
- if (!_frame)
- _frame = new uint16[_header.width * _header.height];
-
uint8 *src = _vptr;
uint8 *end = _vptr + _vptrSize;
@@ -828,20 +837,20 @@ bool VQADecoder::decodeFrame(uint16 *frame)
count = 2 * (((command >> 8) & 0x1f) + 1);
srcBlock = command & 0x00ff;
- VPTRWriteBlock(_frame, dstBlock, srcBlock, count);
+ VPTRWriteBlock(frame, dstBlock, srcBlock, count);
dstBlock += count;
break;
case 2:
count = 2 * (((command >> 8) & 0x1f) + 1);
srcBlock = command & 0x00ff;
- VPTRWriteBlock(_frame, dstBlock, srcBlock, 1);
+ VPTRWriteBlock(frame, dstBlock, srcBlock, 1);
++dstBlock;
for (int i = 0; i < count; ++i)
{
srcBlock = *src++;
- VPTRWriteBlock(_frame, dstBlock, srcBlock, 1);
+ VPTRWriteBlock(frame, dstBlock, srcBlock, 1);
++dstBlock;
}
break;
@@ -850,7 +859,7 @@ bool VQADecoder::decodeFrame(uint16 *frame)
count = 1;
srcBlock = command & 0x1fff;
- VPTRWriteBlock(_frame, dstBlock, srcBlock, count, prefix == 4);
+ VPTRWriteBlock(frame, dstBlock, srcBlock, count, prefix == 4);
++dstBlock;
break;
case 5:
@@ -858,7 +867,7 @@ bool VQADecoder::decodeFrame(uint16 *frame)
count = *src++;
srcBlock = command & 0x1fff;
- VPTRWriteBlock(_frame, dstBlock, srcBlock, count, prefix == 6);
+ VPTRWriteBlock(frame, dstBlock, srcBlock, count, prefix == 6);
dstBlock += count;
break;
default:
@@ -866,14 +875,51 @@ bool VQADecoder::decodeFrame(uint16 *frame)
}
}
- memcpy(frame, _frame, 2 * 640 * 480);
+ return true;
+}
+
+VQADecoder::VQAAudioTrack::VQAAudioTrack(VQADecoder *vqaDecoder) {
+ _audioStream = Audio::makeQueuingAudioStream(vqaDecoder->_header.freq, false);
+}
+
+VQADecoder::VQAAudioTrack::~VQAAudioTrack() {
+ delete _audioStream;
+}
+
+Audio::AudioStream *VQADecoder::VQAAudioTrack::getAudioStream() const {
+ return _audioStream;
+}
+
+bool VQADecoder::VQAAudioTrack::readSND2(Common::SeekableReadStream *s, uint32 size)
+{
+ if (size != 735) {
+ error("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;
}
-int16 *VQADecoder::getAudioFrame()
+bool VQADecoder::VQAAudioTrack::readSN2J(Common::SeekableReadStream *s, uint32 size)
{
- return _audioFrame;
+ if (size != 6)
+ return false;
+
+ uint16 stepIndex = s->readUint16LE();
+ uint32 predictor = s->readUint32LE();
+
+ _adpcmDecoder.setParameters(stepIndex >> 5, predictor);
+
+ return true;
}
}; // End of namespace BladeRunner
diff --git a/engines/bladerunner/vqa_decoder.h b/engines/bladerunner/vqa_decoder.h
index ab1f9efe4d..a2237cc1fa 100644
--- a/engines/bladerunner/vqa_decoder.h
+++ b/engines/bladerunner/vqa_decoder.h
@@ -23,15 +23,33 @@
#ifndef BLADERUNNER_VQA_DECODER_H
#define BLADERUNNER_VQA_DECODER_H
+#include "bladerunner/aud_decoder.h"
+
+#include "audio/audiostream.h"
+
#include "common/debug.h"
#include "common/str.h"
#include "common/stream.h"
#include "common/types.h"
+#include "graphics/surface.h"
+
+#include "video/video_decoder.h"
+
namespace BladeRunner {
-class VQADecoder
+class VQADecoder : public Video::VideoDecoder
{
+public:
+ VQADecoder();
+ ~VQADecoder();
+
+ bool loadStream(Common::SeekableReadStream *s);
+
+protected:
+ void readNextPacket();
+
+private:
struct Header
{
uint16 version; // 0x00
@@ -45,8 +63,8 @@ class VQADecoder
uint8 cbParts; // 0x0D
uint16 colors; // 0x0E
uint16 maxBlocks; // 0x10
- uint16 offset_x; // 0x12
- uint16 offset_y; // 0x14
+ uint16 offsetX; // 0x12
+ uint16 offsetY; // 0x14
uint16 maxVPTRSize; // 0x16
uint16 freq; // 0x18
uint8 channels; // 0x1A
@@ -85,60 +103,109 @@ class VQADecoder
uint16 clipCount;
};
+ class VQAVideoTrack;
+ class VQAAudioTrack;
+
Common::SeekableReadStream *_s;
Header _header;
LoopInfo _loopInfo;
ClipInfo _clipInfo;
- uint16 *_frame;
- uint16 *_zbuf;
-
- size_t _codebookSize;
- uint8 *_codebook;
- uint8 *_cbfz;
-
- size_t _vptrSize;
- uint8 *_vptr;
-
uint32 *_frameInfo;
uint32 _maxVIEWChunkSize;
uint32 _maxZBUFChunkSize;
uint32 _maxAESCChunkSize;
- uint8 *_zbufChunk;
- bool _hasView;
+ VQAVideoTrack *_videoTrack;
+ VQAAudioTrack *_audioTrack;
+
+ // bool _hasView;
// view_t view;
- // ima_adpcm_ws_decoder_t ima_adpcm_ws_decoder;
- int16 *_audioFrame;
-
- bool readVQHD(uint32 size);
- bool readMSCI(uint32 size);
- bool readMFCI(uint32 size);
- bool readLINF(uint32 size);
- bool readCINF(uint32 size);
- bool readFINF(uint32 size);
- bool readLNIN(uint32 size);
- bool readCLIP(uint32 size);
-
- bool readSN2J(uint32 size);
- bool readSND2(uint32 size);
- bool readVQFR(uint32 size);
- bool readVPTR(uint32 size);
- bool readVQFL(uint32 size);
- bool readCBFZ(uint32 size);
- bool readZBUF(uint32 size);
- bool readVIEW(uint32 size);
- bool readAESC(uint32 size);
- bool readLITE(uint32 size);
+ bool readVQHD(Common::SeekableReadStream *s, uint32 size);
+ bool readMSCI(Common::SeekableReadStream *s, uint32 size);
+ bool readMFCI(Common::SeekableReadStream *s, uint32 size);
+ bool readLINF(Common::SeekableReadStream *s, uint32 size);
+ bool readCINF(Common::SeekableReadStream *s, uint32 size);
+ bool readFINF(Common::SeekableReadStream *s, uint32 size);
+ bool readLNIN(Common::SeekableReadStream *s, uint32 size);
+ bool readCLIP(Common::SeekableReadStream *s, uint32 size);
+
+ class VQAVideoTrack : public FixedRateVideoTrack {
+ public:
+ VQAVideoTrack(VQADecoder *vqaDecoder);
+ ~VQAVideoTrack();
+
+ uint16 getWidth() const;
+ uint16 getHeight() const;
+ Graphics::PixelFormat getPixelFormat() const;
+ int getCurFrame() const;
+ int getFrameCount() const;
+ const Graphics::Surface *decodeNextFrame();
+
+ bool readVQFR(Common::SeekableReadStream *s, uint32 size);
+ bool readVPTR(Common::SeekableReadStream *s, uint32 size);
+ bool readVQFL(Common::SeekableReadStream *s, uint32 size);
+ bool readCBFZ(Common::SeekableReadStream *s, uint32 size);
+ bool readZBUF(Common::SeekableReadStream *s, uint32 size);
+ bool readVIEW(Common::SeekableReadStream *s, uint32 size);
+ bool readAESC(Common::SeekableReadStream *s, uint32 size);
+ bool readLITE(Common::SeekableReadStream *s, uint32 size);
+
+ protected:
+ Common::Rational getFrameRate() const;
+
+ private:
+ Graphics::Surface *_surface;
+ bool _hasNewFrame;
+
+ uint16 _numFrames;
+ uint16 _width, _height;
+ uint8 _blockW, _blockH;
+ uint8 _frameRate;
+ uint16 _maxBlocks;
+ uint16 _offsetX, _offsetY;
+
+ uint16 _maxVPTRSize;
+ uint32 _maxCBFZSize;
+ uint32 _maxZBUFChunkSize;
+
+ size_t _codebookSize;
+ uint8 *_codebook;
+ uint8 *_cbfz;
+ uint8 *_zbufChunk;
+
+ size_t _vptrSize;
+ uint8 *_vptr;
+
+ int _curFrame;
+
+
+ void VPTRWriteBlock(uint16 *frame, unsigned int dstBlock, unsigned int srcBlock, int count, bool alpha = false);
+ bool decodeFrame(uint16 *frame);
+ };
-public:
- VQADecoder();
- ~VQADecoder();
+ class VQAAudioTrack : public AudioTrack {
+ public:
+ VQAAudioTrack(VQADecoder *vqaDecoder);
+ ~VQAAudioTrack();
+
+ bool readSND2(Common::SeekableReadStream *s, uint32 size);
+ bool readSN2J(Common::SeekableReadStream *s, uint32 size);
+
+ protected:
+ Audio::AudioStream *getAudioStream() const;
+
+ private:
+ Audio::QueuingAudioStream *_audioStream;
+
+ ADPCMWestwoodDecoder _adpcmDecoder;
+ uint8 _compressedAudioFrame[735];
+ };
- bool open(Common::SeekableReadStream *s);
+/*
bool readFrame();
int getFrameTime() { return 1000 / _header.frameRate; }
@@ -154,6 +221,7 @@ public:
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 8b614813a7..f05e14ba44 100644
--- a/engines/bladerunner/vqa_player.cpp
+++ b/engines/bladerunner/vqa_player.cpp
@@ -24,6 +24,8 @@
#include "bladerunner/bladerunner.h"
+#include "audio/decoders/raw.h"
+
#include "common/system.h"
namespace BladeRunner {
@@ -39,6 +41,8 @@ bool VQAPlayer::open(const Common::String &name) {
return false;
}
+ _audioStream = Audio::makeQueuingAudioStream(_decoder._header.freq, _decoder._header.channels == 2);
+
return true;
}
@@ -78,12 +82,31 @@ int VQAPlayer::update() {
else
++_curFrame;
- if (_curFrame >= _decoder._header.numFrames)
+ if (_curFrame >= _decoder._header.numFrames) {
+ if (_audioStream)
+ _audioStream->finish();
return -3;
+ }
_decoder.readFrame();
_decoder.decodeFrame((uint16*)_surface->getPixels());
+ 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);
+
+ if (!_audioStarted)
+ _vm->_mixer->playStream(
+ Audio::Mixer::kPlainSoundType,
+ &_soundHandle,
+ _audioStream,
+ -1
+ );
+
+ _audioStarted = true;
+ }
+
return _curFrame;
}
diff --git a/engines/bladerunner/vqa_player.h b/engines/bladerunner/vqa_player.h
index 2d7d6822b3..7e7fab5b5f 100644
--- a/engines/bladerunner/vqa_player.h
+++ b/engines/bladerunner/vqa_player.h
@@ -26,6 +26,7 @@
#include "bladerunner/vqa_decoder.h"
#include "audio/audiostream.h"
+#include "audio/mixer.h"
#include "graphics/surface.h"
@@ -46,6 +47,8 @@ class VQAPlayer {
int _loopDefault;
uint32 _nextFrameTime;
+ bool _audioStarted;
+ Audio::SoundHandle _soundHandle;
public:
@@ -58,7 +61,8 @@ public:
_curLoop(-1),
_loopSpecial(-1),
_loopDefault(-1),
- _nextFrameTime(0)
+ _nextFrameTime(0),
+ _audioStarted(false)
{}
bool open(const Common::String &name);