[Scummvm-cvs-logs] scummvm master -> 4637d55337d083d85bea762db7d59b47e92c0fbe
wjp
wjp at usecode.org
Thu Feb 23 23:00:22 CET 2012
This automated email contains information about 9 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
307908662a VIDEO: Add a PlayStation stream decoder
df21e72fe2 SWORD1: Add support for PSX stream playback
8812f885bc SWORD2: Add support for PSX stream playback
ee35d32a36 VIDEO: Implement PSX stream v3 frame support
66cd8bdd68 VIDEO: Make PSX streams calculate frame timing solely from CD speed
8fea496890 VIDEO: Clarify which PSX streams we can play
a352c3cc00 SWORD1: Add support for the PSX demo videos
7a3e0ea453 SWORD1: Add some TODO's for PSX stream subtitles
4637d55337 Merge pull request #171 from clone2727/psx-stream-2
Commit: 307908662af4f171e442e3b6b209e72845f30c06
https://github.com/scummvm/scummvm/commit/307908662af4f171e442e3b6b209e72845f30c06
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2012-02-23T13:48:16-08:00
Commit Message:
VIDEO: Add a PlayStation stream decoder
To be used for sword1/sword2 PSX video playback
Changed paths:
A video/psx_decoder.cpp
A video/psx_decoder.h
video/module.mk
diff --git a/video/module.mk b/video/module.mk
index ceeac94..900a781 100644
--- a/video/module.mk
+++ b/video/module.mk
@@ -5,6 +5,7 @@ MODULE_OBJS := \
coktel_decoder.o \
dxa_decoder.o \
flic_decoder.o \
+ psx_decoder.o \
qt_decoder.o \
smk_decoder.o \
video_decoder.o \
diff --git a/video/psx_decoder.cpp b/video/psx_decoder.cpp
new file mode 100644
index 0000000..4ed5a16
--- /dev/null
+++ b/video/psx_decoder.cpp
@@ -0,0 +1,638 @@
+/* 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.
+ *
+ */
+
+// PlayStation Stream demuxer and XA audio decoder based on FFmpeg/libav
+// MDEC video emulation based on http://kenai.com/downloads/jpsxdec/Old/PlayStation1_STR_format1-00.txt
+
+#include "audio/audiostream.h"
+#include "audio/mixer.h"
+#include "audio/decoders/raw.h"
+#include "common/bitstream.h"
+#include "common/huffman.h"
+#include "common/memstream.h"
+#include "common/stream.h"
+#include "common/system.h"
+#include "common/textconsole.h"
+#include "graphics/yuv_to_rgb.h"
+
+#include "video/psx_decoder.h"
+
+namespace Video {
+
+PSXStreamDecoder::PSXStreamDecoder(Common::Rational frameRate) {
+ assert(frameRate != 0);
+ initCommon();
+ _frameRate = frameRate;
+ _frameCount = 0;
+ _speed = kCDUnk;
+}
+
+PSXStreamDecoder::PSXStreamDecoder(CDSpeed speed, uint32 frameCount) {
+ assert(speed != kCDUnk);
+ assert(frameCount != 0);
+ initCommon();
+ _frameCount = frameCount;
+ _speed = speed;
+ // frame rate will be calculated in loadStream()
+}
+
+PSXStreamDecoder::~PSXStreamDecoder() {
+ close();
+ delete _surface;
+ delete _huffman;
+}
+
+#define CODE_COUNT 113
+#define HUFFVAL(z, a) ((z << 8) | a)
+#define ESCAPE_CODE ((uint32)-1) // arbitrary, just so we can tell what code it is
+#define END_OF_BLOCK ((uint32)-2) // arbitrary, just so we can tell what code it is
+#define GET_ZEROES(code) (code >> 8)
+#define GET_AC(code) ((int)(code & 0xff))
+
+static const uint32 s_huffmanCodes[CODE_COUNT] = {
+ // Regular codes
+ 3, 3, 4, 5, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7,
+ 32, 33, 34, 35, 36, 37, 38, 39, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
+ 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31,
+
+ // Escape code
+ 1,
+ // End of block code
+ 2
+};
+
+static const byte s_huffmanLengths[CODE_COUNT] = {
+ // Regular codes
+ 2, 3, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10,
+ 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16,
+
+ // Escape code
+ 6,
+ // End of block code
+ 2
+};
+
+static const uint32 s_huffmanSymbols[CODE_COUNT] = {
+ // Regular codes
+ HUFFVAL(0, 1), HUFFVAL(1, 1), HUFFVAL(0, 2), HUFFVAL(2, 1), HUFFVAL(0, 3),
+ HUFFVAL(4, 1), HUFFVAL(3, 1), HUFFVAL(7, 1), HUFFVAL(6, 1), HUFFVAL(1, 2),
+ HUFFVAL(5, 1), HUFFVAL(2, 2), HUFFVAL(9, 1), HUFFVAL(0, 4), HUFFVAL(8, 1),
+ HUFFVAL(13, 1), HUFFVAL(0, 6), HUFFVAL(12, 1), HUFFVAL(11, 1), HUFFVAL(3, 2),
+ HUFFVAL(1, 3), HUFFVAL(0, 5), HUFFVAL(10, 1), HUFFVAL(16, 1), HUFFVAL(5, 2),
+ HUFFVAL(0, 7), HUFFVAL(2, 3), HUFFVAL(1, 4), HUFFVAL(15, 1), HUFFVAL(14, 1),
+ HUFFVAL(4, 2), HUFFVAL(0, 11), HUFFVAL(8, 2), HUFFVAL(4, 3), HUFFVAL(0, 10),
+ HUFFVAL(2, 4), HUFFVAL(7, 2), HUFFVAL(21, 1), HUFFVAL(20, 1), HUFFVAL(0, 9),
+ HUFFVAL(19, 1), HUFFVAL(18, 1), HUFFVAL(1, 5), HUFFVAL(3, 3), HUFFVAL(0, 8),
+ HUFFVAL(6, 2), HUFFVAL(17, 1), HUFFVAL(10, 2), HUFFVAL(9, 2), HUFFVAL(5, 3),
+ HUFFVAL(3, 4), HUFFVAL(2, 5), HUFFVAL(1, 7), HUFFVAL(1, 6), HUFFVAL(0, 15),
+ HUFFVAL(0, 14), HUFFVAL(0, 13), HUFFVAL(0, 12), HUFFVAL(26, 1), HUFFVAL(25, 1),
+ HUFFVAL(24, 1), HUFFVAL(23, 1), HUFFVAL(22, 1), HUFFVAL(0, 31), HUFFVAL(0, 30),
+ HUFFVAL(0, 29), HUFFVAL(0, 28), HUFFVAL(0, 27), HUFFVAL(0, 26), HUFFVAL(0, 25),
+ HUFFVAL(0, 24), HUFFVAL(0, 23), HUFFVAL(0, 22), HUFFVAL(0, 21), HUFFVAL(0, 20),
+ HUFFVAL(0, 19), HUFFVAL(0, 18), HUFFVAL(0, 17), HUFFVAL(0, 16), HUFFVAL(0, 40),
+ HUFFVAL(0, 39), HUFFVAL(0, 38), HUFFVAL(0, 37), HUFFVAL(0, 36), HUFFVAL(0, 35),
+ HUFFVAL(0, 34), HUFFVAL(0, 33), HUFFVAL(0, 32), HUFFVAL(1, 14), HUFFVAL(1, 13),
+ HUFFVAL(1, 12), HUFFVAL(1, 11), HUFFVAL(1, 10), HUFFVAL(1, 9), HUFFVAL(1, 8),
+ HUFFVAL(1, 18), HUFFVAL(1, 17), HUFFVAL(1, 16), HUFFVAL(1, 15), HUFFVAL(6, 3),
+ HUFFVAL(16, 2), HUFFVAL(15, 2), HUFFVAL(14, 2), HUFFVAL(13, 2), HUFFVAL(12, 2),
+ HUFFVAL(11, 2), HUFFVAL(31, 1), HUFFVAL(30, 1), HUFFVAL(29, 1), HUFFVAL(28, 1),
+ HUFFVAL(27, 1),
+
+ // Escape code
+ ESCAPE_CODE,
+ // End of block code
+ END_OF_BLOCK
+};
+
+void PSXStreamDecoder::initCommon() {
+ _stream = 0;
+ _audStream = 0;
+ _surface = new Graphics::Surface();
+ _yBuffer = _cbBuffer = _crBuffer = 0;
+ _huffman = new Common::Huffman(0, CODE_COUNT, s_huffmanCodes, s_huffmanLengths, s_huffmanSymbols);
+}
+
+#define RAW_CD_SECTOR_SIZE 2352
+
+#define CDXA_TYPE_MASK 0x0E
+#define CDXA_TYPE_DATA 0x08
+#define CDXA_TYPE_AUDIO 0x04
+#define CDXA_TYPE_VIDEO 0x02
+
+bool PSXStreamDecoder::loadStream(Common::SeekableReadStream *stream) {
+ close();
+
+ _stream = stream;
+
+ Common::SeekableReadStream *sector = readSector();
+
+ if (!sector) {
+ close();
+ return false;
+ }
+
+ // Rip out video info from the first frame
+ sector->seek(18);
+ byte sectorType = sector->readByte() & CDXA_TYPE_MASK;
+
+ if (sectorType != CDXA_TYPE_VIDEO && sectorType != CDXA_TYPE_DATA) {
+ close();
+ return false;
+ }
+
+ sector->seek(40);
+
+ uint16 width = sector->readUint16LE();
+ uint16 height = sector->readUint16LE();
+ _surface->create(width, height, g_system->getScreenFormat());
+
+ _macroBlocksW = (width + 15) / 16;
+ _macroBlocksH = (height + 15) / 16;
+ _yBuffer = new byte[_macroBlocksW * _macroBlocksH * 16 * 16];
+ _cbBuffer = new byte[_macroBlocksW * _macroBlocksH * 8 * 8];
+ _crBuffer = new byte[_macroBlocksW * _macroBlocksH * 8 * 8];
+
+ delete sector;
+ _stream->seek(0);
+
+ // Calculate frame rate based on CD speed
+ if (_speed != kCDUnk) {
+ // TODO: This algorithm is too basic and not accurate enough
+ // TODO: Count the number of sectors per frame to get a better estimate
+ _frameRate = Common::Rational(_speed * _frameCount, _stream->size() / RAW_CD_SECTOR_SIZE);
+ _frameRate.debugPrint(0, "Approximate PSX Stream Frame Rate:");
+ }
+
+ return true;
+}
+
+void PSXStreamDecoder::close() {
+ if (!_stream)
+ return;
+
+ delete _stream;
+ _stream = 0;
+
+ // Deinitialize sound
+ g_system->getMixer()->stopHandle(_audHandle);
+ _audStream = 0;
+
+ _surface->free();
+
+ memset(&_adpcmStatus, 0, sizeof(_adpcmStatus));
+
+ _macroBlocksW = _macroBlocksH = 0;
+ delete[] _yBuffer; _yBuffer = 0;
+ delete[] _cbBuffer; _cbBuffer = 0;
+ delete[] _crBuffer; _crBuffer = 0;
+
+ reset();
+}
+
+uint32 PSXStreamDecoder::getElapsedTime() const {
+ // TODO: Currently, the audio is always after the video so using this
+ // can often lead to gaps in the audio...
+ //if (_audStream)
+ // return _mixer->getSoundElapsedTime(_audHandle);
+
+ return FixedRateVideoDecoder::getElapsedTime();
+}
+
+#define VIDEO_DATA_CHUNK_SIZE 2016
+#define VIDEO_DATA_HEADER_SIZE 56
+
+const Graphics::Surface *PSXStreamDecoder::decodeNextFrame() {
+ Common::SeekableReadStream *sector = 0;
+ byte *partialFrame = 0;
+
+ while (!endOfVideo()) {
+ sector = readSector();
+
+ if (!sector)
+ error("Corrupt PSX stream sector");
+
+ sector->seek(0x11);
+ byte track = sector->readByte();
+ if (track >= 32)
+ error("Bad PSX stream track");
+
+ byte sectorType = sector->readByte() & CDXA_TYPE_MASK;
+
+ switch (sectorType) {
+ case CDXA_TYPE_DATA:
+ case CDXA_TYPE_VIDEO:
+ if (track == 1) {
+ sector->seek(28);
+ uint16 curSector = sector->readUint16LE();
+ uint16 sectorCount = sector->readUint16LE();
+ sector->readUint32LE();
+ uint16 frameSize = sector->readUint32LE();
+
+ if (curSector >= sectorCount)
+ error("Bad sector");
+
+ if (!partialFrame)
+ partialFrame = (byte *)malloc(sectorCount * VIDEO_DATA_CHUNK_SIZE);
+
+ sector->seek(VIDEO_DATA_HEADER_SIZE);
+ sector->read(partialFrame + curSector * VIDEO_DATA_CHUNK_SIZE, VIDEO_DATA_CHUNK_SIZE);
+
+ if (curSector == sectorCount - 1) {
+ // Done assembling the frame
+ Common::SeekableReadStream *frame = new Common::MemoryReadStream(partialFrame, frameSize, DisposeAfterUse::YES);
+
+ decodeFrame(frame);
+
+ delete frame;
+ delete sector;
+
+ _curFrame++;
+ if (_curFrame == 0)
+ _startTime = g_system->getMillis();
+
+ return _surface;
+ }
+ } else
+ error("Unhandled multi-track video");
+ break;
+ case CDXA_TYPE_AUDIO:
+ // We only handle one audio channel so far
+ if (track == 1)
+ queueAudioFromSector(sector);
+ else
+ warning("Unhandled multi-track audio");
+ break;
+ default:
+ // This shows up way too often, but the other sectors
+ // are safe to ignore
+ //warning("Unknown PSX sector type 0x%x", sectorType);
+ break;
+ }
+
+ delete sector;
+ }
+
+ return 0;
+}
+
+static const byte s_syncHeader[12] = { 0x00, 0xff ,0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
+
+Common::SeekableReadStream *PSXStreamDecoder::readSector() {
+ assert(_stream);
+
+ Common::SeekableReadStream *stream = _stream->readStream(RAW_CD_SECTOR_SIZE);
+
+ byte syncHeader[12];
+ stream->read(syncHeader, 12);
+ if (!memcmp(s_syncHeader, syncHeader, 12))
+ return stream;
+
+ return 0;
+}
+
+// Ha! It's palindromic!
+#define AUDIO_DATA_CHUNK_SIZE 2304
+#define AUDIO_DATA_SAMPLE_COUNT 4032
+
+static const int s_xaTable[5][2] = {
+ { 0, 0 },
+ { 60, 0 },
+ { 115, -52 },
+ { 98, -55 },
+ { 122, -60 }
+};
+
+void PSXStreamDecoder::queueAudioFromSector(Common::SeekableReadStream *sector) {
+ assert(sector);
+
+ if (!_audStream) {
+ // Initialize audio stream
+ sector->seek(19);
+ byte format = sector->readByte();
+
+ bool stereo = (format & (1 << 0)) != 0;
+ uint rate = (format & (1 << 2)) ? 18900 : 37800;
+
+ _audStream = Audio::makeQueuingAudioStream(rate, stereo);
+ g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_audHandle, _audStream);
+ }
+
+ sector->seek(24);
+
+ // This XA audio is different (yet similar) from normal XA audio! Watch out!
+ // TODO: It's probably similar enough to normal XA that we can merge it somehow...
+ // TODO: RTZ PSX needs the same audio code in a regular AudioStream class. Probably
+ // will do something similar to QuickTime and creating a base class 'ISOMode2Parser'
+ // or something similar.
+ byte *buf = new byte[AUDIO_DATA_CHUNK_SIZE];
+ sector->read(buf, AUDIO_DATA_CHUNK_SIZE);
+
+ int channels = _audStream->isStereo() ? 2 : 1;
+ int16 *dst = new int16[AUDIO_DATA_SAMPLE_COUNT];
+ int16 *leftChannel = dst;
+ int16 *rightChannel = dst + 1;
+
+ for (byte *src = buf; src < buf + AUDIO_DATA_CHUNK_SIZE; src += 128) {
+ for (int i = 0; i < 4; i++) {
+ int shift = 12 - (src[4 + i * 2] & 0xf);
+ int filter = src[4 + i * 2] >> 4;
+ int f0 = s_xaTable[filter][0];
+ int f1 = s_xaTable[filter][1];
+ int16 s_1 = _adpcmStatus[0].sample[0];
+ int16 s_2 = _adpcmStatus[0].sample[1];
+
+ for (int j = 0; j < 28; j++) {
+ byte d = src[16 + i + j * 4];
+ int t = (int8)(d << 4) >> 4;
+ int s = (t << shift) + ((s_1 * f0 + s_2 * f1 + 32) >> 6);
+ s_2 = s_1;
+ s_1 = CLIP<int>(s, -32768, 32767);
+ *leftChannel = s_1;
+ leftChannel += channels;
+ }
+
+ if (channels == 2) {
+ _adpcmStatus[0].sample[0] = s_1;
+ _adpcmStatus[0].sample[1] = s_2;
+ s_1 = _adpcmStatus[1].sample[0];
+ s_2 = _adpcmStatus[1].sample[1];
+ }
+
+ shift = 12 - (src[5 + i * 2] & 0xf);
+ filter = src[5 + i * 2] >> 4;
+ f0 = s_xaTable[filter][0];
+ f1 = s_xaTable[filter][1];
+
+ for (int j = 0; j < 28; j++) {
+ byte d = src[16 + i + j * 4];
+ int t = (int8)d >> 4;
+ int s = (t << shift) + ((s_1 * f0 + s_2 * f1 + 32) >> 6);
+ s_2 = s_1;
+ s_1 = CLIP<int>(s, -32768, 32767);
+
+ if (channels == 2) {
+ *rightChannel = s_1;
+ rightChannel += 2;
+ } else {
+ *leftChannel++ = s_1;
+ }
+ }
+
+ if (channels == 2) {
+ _adpcmStatus[1].sample[0] = s_1;
+ _adpcmStatus[1].sample[1] = s_2;
+ } else {
+ _adpcmStatus[0].sample[0] = s_1;
+ _adpcmStatus[0].sample[1] = s_2;
+ }
+ }
+ }
+
+ int flags = Audio::FLAG_16BITS;
+
+ if (_audStream->isStereo())
+ flags |= Audio::FLAG_STEREO;
+
+#ifdef SCUMM_LITTLE_ENDIAN
+ flags |= Audio::FLAG_LITTLE_ENDIAN;
+#endif
+
+ _audStream->queueBuffer((byte *)dst, AUDIO_DATA_SAMPLE_COUNT * 2, DisposeAfterUse::YES, flags);
+ delete[] buf;
+}
+
+void PSXStreamDecoder::decodeFrame(Common::SeekableReadStream *frame) {
+ // A frame is essentially an MPEG-1 intra frame
+
+ Common::BitStream16LEMSB bits(frame);
+
+ bits.skip(16); // unknown
+ bits.skip(16); // 0x3800
+ uint16 scale = bits.getBits(16);
+ uint16 version = bits.getBits(16);
+
+ if (version != 2 && version != 3)
+ error("Unknown PSX stream frame version");
+
+ for (int mbX = 0; mbX < _macroBlocksW; mbX++)
+ for (int mbY = 0; mbY < _macroBlocksH; mbY++)
+ decodeMacroBlock(&bits, mbX, mbY, scale, version);
+
+ // Output data onto the frame
+ Graphics::convertYUV420ToRGB(_surface, _yBuffer, _cbBuffer, _crBuffer, _surface->w, _surface->h, _macroBlocksW * 16, _macroBlocksW * 8);
+}
+
+void PSXStreamDecoder::decodeMacroBlock(Common::BitStream *bits, int mbX, int mbY, uint16 scale, uint16 version) {
+ int pitchY = _macroBlocksW * 16;
+ int pitchC = _macroBlocksW * 8;
+
+ // Note the strange order of red before blue
+ decodeBlock(bits, _crBuffer + (mbY * pitchC + mbX) * 8, pitchC, scale, version);
+ decodeBlock(bits, _cbBuffer + (mbY * pitchC + mbX) * 8, pitchC, scale, version);
+ decodeBlock(bits, _yBuffer + (mbY * pitchY + mbX) * 16, pitchY, scale, version);
+ decodeBlock(bits, _yBuffer + (mbY * pitchY + mbX) * 16 + 8, pitchY, scale, version);
+ decodeBlock(bits, _yBuffer + (mbY * pitchY + mbX) * 16 + 8 * pitchY, pitchY, scale, version);
+ decodeBlock(bits, _yBuffer + (mbY * pitchY + mbX) * 16 + 8 * pitchY + 8, pitchY, scale, version);
+}
+
+// Standard JPEG/MPEG zig zag table
+static const byte s_zigZagTable[8 * 8] = {
+ 0, 1, 5, 6, 14, 15, 27, 28,
+ 2, 4, 7, 13, 16, 26, 29, 42,
+ 3, 8, 12, 17, 25, 30, 41, 43,
+ 9, 11, 18, 24, 31, 40, 44, 53,
+ 10, 19, 23, 32, 39, 45, 52, 54,
+ 20, 22, 33, 38, 46, 51, 55, 60,
+ 21, 34, 37, 47, 50, 56, 59, 61,
+ 35, 36, 48, 49, 57, 58, 62, 63
+};
+
+// One byte different from the standard MPEG-1 table
+static const byte s_quantizationTable[8 * 8] = {
+ 2, 16, 19, 22, 26, 27, 29, 34,
+ 16, 16, 22, 24, 27, 29, 34, 37,
+ 19, 22, 26, 27, 29, 34, 34, 38,
+ 22, 22, 26, 27, 29, 34, 37, 40,
+ 22, 26, 27, 29, 32, 35, 40, 48,
+ 26, 27, 29, 32, 35, 40, 48, 58,
+ 26, 27, 29, 34, 38, 46, 56, 69,
+ 27, 29, 35, 38, 46, 56, 69, 83
+};
+
+void PSXStreamDecoder::dequantizeBlock(int *coefficients, float *block, uint16 scale) {
+ // Dequantize the data, un-zig-zagging as we go along
+ for (int i = 0; i < 8 * 8; i++) {
+ if (i == 0) // Special case for the DC coefficient
+ block[i] = coefficients[i] * s_quantizationTable[i];
+ else
+ block[i] = (float)coefficients[s_zigZagTable[i]] * s_quantizationTable[i] * scale / 8;
+ }
+}
+
+#define BLOCK_OVERFLOW_CHECK() \
+ if (count > 63) \
+ error("PSXStreamDecoder::readAC(): Too many coefficients")
+
+void PSXStreamDecoder::readAC(Common::BitStream *bits, int *block) {
+ // Clear the block first
+ for (int i = 0; i < 63; i++)
+ block[i] = 0;
+
+ int count = 0;
+
+ while (!bits->eos()) {
+ uint32 symbol = _huffman->getSymbol(*bits);
+
+ if (symbol == ESCAPE_CODE) {
+ // The escape code!
+ int zeroes = bits->getBits(6);
+ count += zeroes + 1;
+ BLOCK_OVERFLOW_CHECK();
+ block += zeroes;
+ *block++ = readSignedCoefficient(bits);
+ } else if (symbol == END_OF_BLOCK) {
+ // We're done
+ break;
+ } else {
+ // Normal huffman code
+ int zeroes = GET_ZEROES(symbol);
+ count += zeroes + 1;
+ BLOCK_OVERFLOW_CHECK();
+ block += zeroes;
+
+ if (bits->getBit())
+ *block++ = -GET_AC(symbol);
+ else
+ *block++ = GET_AC(symbol);
+ }
+ }
+}
+
+int PSXStreamDecoder::readSignedCoefficient(Common::BitStream *bits) {
+ uint val = bits->getBits(10);
+
+ // extend the sign
+ uint shift = 8 * sizeof(int) - 10;
+ return (int)(val << shift) >> shift;
+}
+
+// IDCT table built with :
+// _idct8x8[x][y] = cos(((2 * x + 1) * y) * (M_PI / 16.0)) * 0.5;
+// _idct8x8[x][y] /= sqrt(2.0) if y == 0
+static const double s_idct8x8[8][8] = {
+ { 0.353553390593274, 0.490392640201615, 0.461939766255643, 0.415734806151273, 0.353553390593274, 0.277785116509801, 0.191341716182545, 0.097545161008064 },
+ { 0.353553390593274, 0.415734806151273, 0.191341716182545, -0.097545161008064, -0.353553390593274, -0.490392640201615, -0.461939766255643, -0.277785116509801 },
+ { 0.353553390593274, 0.277785116509801, -0.191341716182545, -0.490392640201615, -0.353553390593274, 0.097545161008064, 0.461939766255643, 0.415734806151273 },
+ { 0.353553390593274, 0.097545161008064, -0.461939766255643, -0.277785116509801, 0.353553390593274, 0.415734806151273, -0.191341716182545, -0.490392640201615 },
+ { 0.353553390593274, -0.097545161008064, -0.461939766255643, 0.277785116509801, 0.353553390593274, -0.415734806151273, -0.191341716182545, 0.490392640201615 },
+ { 0.353553390593274, -0.277785116509801, -0.191341716182545, 0.490392640201615, -0.353553390593273, -0.097545161008064, 0.461939766255643, -0.415734806151273 },
+ { 0.353553390593274, -0.415734806151273, 0.191341716182545, 0.097545161008064, -0.353553390593274, 0.490392640201615, -0.461939766255643, 0.277785116509801 },
+ { 0.353553390593274, -0.490392640201615, 0.461939766255643, -0.415734806151273, 0.353553390593273, -0.277785116509801, 0.191341716182545, -0.097545161008064 }
+};
+
+void PSXStreamDecoder::idct(float *dequantData, float *result) {
+ // IDCT code based on JPEG's IDCT code
+ // TODO: Switch to the integer-based one mentioned in the docs
+ // This is by far the costliest operation here
+
+ float tmp[8 * 8];
+
+ // Apply 1D IDCT to rows
+ for (int y = 0; y < 8; y++) {
+ for (int x = 0; x < 8; x++) {
+ tmp[y + x * 8] = dequantData[0] * s_idct8x8[x][0]
+ + dequantData[1] * s_idct8x8[x][1]
+ + dequantData[2] * s_idct8x8[x][2]
+ + dequantData[3] * s_idct8x8[x][3]
+ + dequantData[4] * s_idct8x8[x][4]
+ + dequantData[5] * s_idct8x8[x][5]
+ + dequantData[6] * s_idct8x8[x][6]
+ + dequantData[7] * s_idct8x8[x][7];
+ }
+
+ dequantData += 8;
+ }
+
+ // Apply 1D IDCT to columns
+ for (int x = 0; x < 8; x++) {
+ const float *u = tmp + x * 8;
+ for (int y = 0; y < 8; y++) {
+ result[y * 8 + x] = u[0] * s_idct8x8[y][0]
+ + u[1] * s_idct8x8[y][1]
+ + u[2] * s_idct8x8[y][2]
+ + u[3] * s_idct8x8[y][3]
+ + u[4] * s_idct8x8[y][4]
+ + u[5] * s_idct8x8[y][5]
+ + u[6] * s_idct8x8[y][6]
+ + u[7] * s_idct8x8[y][7];
+ }
+ }
+}
+
+void PSXStreamDecoder::decodeBlock(Common::BitStream *bits, byte *block, int pitch, uint16 scale, uint16 version) {
+ int dc;
+
+ if (version == 2) {
+ dc = readSignedCoefficient(bits);
+ } else {
+ // TODO
+ error("Unhandled PSX stream version 3 DC");
+ }
+
+ int coefficients[8 * 8];
+ coefficients[0] = dc; // Start us off with the DC
+ readAC(bits, &coefficients[1]); // Read in the AC
+
+ // Dequantize
+ float dequantData[8 * 8];
+ dequantizeBlock(coefficients, dequantData, scale);
+
+ // Perform IDCT
+ float idctData[8 * 8];
+ idct(dequantData, idctData);
+
+ // Now output the data
+ for (int y = 0; y < 8; y++) {
+ byte *start = block + pitch * y;
+
+ // Convert the result to be in the range [0, 255]
+ for (int x = 0; x < 8; x++)
+ *start++ = (int)CLIP<float>(idctData[y * 8 + x], -128.0f, 127.0f) + 128;
+ }
+}
+
+} // End of namespace Video
diff --git a/video/psx_decoder.h b/video/psx_decoder.h
new file mode 100644
index 0000000..e8de507
--- /dev/null
+++ b/video/psx_decoder.h
@@ -0,0 +1,120 @@
+/* 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 VIDEO_PSX_DECODER_H
+#define VIDEO_PSX_DECODER_H
+
+#include "common/endian.h"
+#include "common/rational.h"
+#include "common/rect.h"
+#include "common/str.h"
+#include "graphics/surface.h"
+#include "video/video_decoder.h"
+
+namespace Audio {
+class QueuingAudioStream;
+}
+
+namespace Common {
+class BitStream;
+class Huffman;
+class SeekableReadStream;
+}
+
+namespace Graphics {
+struct PixelFormat;
+}
+
+namespace Video {
+
+/**
+ * Decoder for PSX stream videos.
+ *
+ * Video decoder used in engines:
+ * - sword1 (psx)
+ * - sword2 (psx)
+ */
+class PSXStreamDecoder : public FixedRateVideoDecoder {
+public:
+ // CD speed in sectors/second
+ // Calling code should use these enum values instead of the constants
+ enum CDSpeed {
+ kCDUnk = 0,
+ kCD1x = 75,
+ kCD2x = 150
+ };
+
+ PSXStreamDecoder(Common::Rational frameRate);
+ PSXStreamDecoder(CDSpeed speed, uint32 frameCount);
+ virtual ~PSXStreamDecoder();
+
+ bool loadStream(Common::SeekableReadStream *stream);
+ void close();
+
+ bool isVideoLoaded() const { return _stream != 0; }
+ uint16 getWidth() const { return _surface->w; }
+ uint16 getHeight() const { return _surface->h; }
+ uint32 getFrameCount() const { return _frameCount; }
+ uint32 getElapsedTime() const;
+ const Graphics::Surface *decodeNextFrame();
+ Graphics::PixelFormat getPixelFormat() const { return _surface->format; }
+ bool endOfVideo() const { return _stream->pos() >= _stream->size(); }
+
+protected:
+ // Hardcoded frame rate
+ Common::Rational getFrameRate() const { return _frameRate; }
+
+private:
+ void initCommon();
+ Common::SeekableReadStream *_stream;
+ Graphics::Surface *_surface;
+
+ CDSpeed _speed;
+ uint32 _frameCount;
+ Common::Rational _frameRate;
+
+ Audio::SoundHandle _audHandle;
+ Audio::QueuingAudioStream *_audStream;
+ void queueAudioFromSector(Common::SeekableReadStream *sector);
+
+ Common::Huffman *_huffman;
+ uint16 _macroBlocksW, _macroBlocksH;
+ byte *_yBuffer, *_cbBuffer, *_crBuffer;
+ void decodeFrame(Common::SeekableReadStream *frame);
+ void decodeMacroBlock(Common::BitStream *bits, int mbX, int mbY, uint16 scale, uint16 version);
+ void decodeBlock(Common::BitStream *bits, byte *block, int pitch, uint16 scale, uint16 version);
+
+ void dequantizeBlock(int *coefficients, float *block, uint16 scale);
+ void readAC(Common::BitStream *bits, int *block);
+ void idct(float *dequantData, float *result);
+ int readSignedCoefficient(Common::BitStream *bits);
+
+ struct ADPCMStatus {
+ int16 sample[2];
+ } _adpcmStatus[2];
+
+ Common::SeekableReadStream *readSector();
+};
+
+} // End of namespace Video
+
+#endif
Commit: df21e72fe22132a802856bccc5f4bba27e4d3c17
https://github.com/scummvm/scummvm/commit/df21e72fe22132a802856bccc5f4bba27e4d3c17
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2012-02-23T13:48:17-08:00
Commit Message:
SWORD1: Add support for PSX stream playback
Changed paths:
engines/sword1/animation.cpp
engines/sword1/animation.h
engines/sword1/sword1.cpp
diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp
index d55a082..9e190e0 100644
--- a/engines/sword1/animation.cpp
+++ b/engines/sword1/animation.cpp
@@ -37,6 +37,11 @@
#include "gui/message.h"
+#include "video/psx_decoder.h"
+#include "video/smk_decoder.h"
+
+#include "engines/util.h"
+
namespace Sword1 {
static const char *const sequenceList[20] = {
@@ -62,6 +67,31 @@ static const char *const sequenceList[20] = {
"credits", // 19 CD2 credits, to follow "finale" sequence
};
+// This is the list of the names of the PlayStation videos
+// TODO: fight.str, flashy.str,
+static const char *const sequenceListPSX[20] = {
+ "e_ferr1",
+ "ladder1",
+ "steps1",
+ "sewer1",
+ "e_intro1",
+ "river1",
+ "truck1",
+ "grave1",
+ "montfcn1",
+ "tapesty1",
+ "ireland1",
+ "e_fin1",
+ "e_hist1",
+ "spanish1",
+ "well1",
+ "candle1",
+ "geodrop1",
+ "vulture1",
+ "",
+ "" // no credits?
+};
+
///////////////////////////////////////////////////////////////////////////////
// Basic movie player
///////////////////////////////////////////////////////////////////////////////
@@ -72,8 +102,8 @@ MoviePlayer::MoviePlayer(SwordEngine *vm, Text *textMan, ResMan *resMan, Audio::
_decoderType = decoderType;
_decoder = decoder;
- _white = 255;
- _black = 0;
+ _white = (decoderType == kVideoDecoderPSX) ? _system->getScreenFormat().RGBToColor(0xff, 0xff, 0xff) : 255;
+ _black = (decoderType == kVideoDecoderPSX) ? _system->getScreenFormat().RGBToColor(0x00, 0x00, 0x00) : 0;
}
MoviePlayer::~MoviePlayer() {
@@ -142,6 +172,21 @@ bool MoviePlayer::load(uint32 id) {
case kVideoDecoderSMK:
filename = Common::String::format("%s.smk", sequenceList[id]);
break;
+ case kVideoDecoderPSX:
+ filename = Common::String::format("%s.str", sequenceListPSX[id]);
+
+ // Need to switch to true color
+ initGraphics(g_system->getWidth(), g_system->getHeight(), true, 0);
+
+ // Need to load here in case it fails in which case we'd need
+ // to go back to paletted mode
+ if (_decoder->loadFile(filename)) {
+ return true;
+ } else {
+ initGraphics(g_system->getWidth(), g_system->getHeight(), true);
+ return false;
+ }
+ break;
}
return _decoder->loadFile(filename.c_str());
@@ -179,6 +224,10 @@ void MoviePlayer::play() {
}
void MoviePlayer::performPostProcessing(byte *screen) {
+ // TODO
+ if (_decoderType == kVideoDecoderPSX)
+ return;
+
if (!_movieTexts.empty()) {
if (_decoder->getCurFrame() == _movieTexts.front()._startFrame) {
_textMan->makeTextSprite(2, (const uint8 *)_movieTexts.front()._text.c_str(), 600, LETTER_COL);
@@ -206,10 +255,10 @@ void MoviePlayer::performPostProcessing(byte *screen) {
for (x = 0; x < _textWidth; x++) {
switch (src[x]) {
case BORDER_COL:
- dst[x] = findBlackPalIndex();
+ dst[x] = getBlackColor();
break;
case LETTER_COL:
- dst[x] = findWhitePalIndex();
+ dst[x] = getWhiteColor();
break;
}
}
@@ -229,12 +278,12 @@ void MoviePlayer::performPostProcessing(byte *screen) {
for (y = 0; y < _textHeight; y++) {
if (_textY + y < frameY || _textY + y >= frameY + frameHeight) {
- memset(dst + _textX, findBlackPalIndex(), _textWidth);
+ memset(dst + _textX, getBlackColor(), _textWidth);
} else {
if (frameX > _textX)
- memset(dst + _textX, findBlackPalIndex(), frameX - _textX);
+ memset(dst + _textX, getBlackColor(), frameX - _textX);
if (frameX + frameWidth < _textX + _textWidth)
- memset(dst + frameX + frameWidth, findBlackPalIndex(), _textX + _textWidth - (frameX + frameWidth));
+ memset(dst + frameX + frameWidth, getBlackColor(), _textX + _textWidth - (frameX + frameWidth));
}
dst += _system->getWidth();
@@ -246,14 +295,19 @@ void MoviePlayer::performPostProcessing(byte *screen) {
}
bool MoviePlayer::playVideo() {
+ bool skipped = false;
uint16 x = (g_system->getWidth() - _decoder->getWidth()) / 2;
uint16 y = (g_system->getHeight() - _decoder->getHeight()) / 2;
- while (!_vm->shouldQuit() && !_decoder->endOfVideo()) {
+ while (!_vm->shouldQuit() && !_decoder->endOfVideo() && !skipped) {
if (_decoder->needsUpdate()) {
const Graphics::Surface *frame = _decoder->decodeNextFrame();
- if (frame)
- _vm->_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h);
+ if (frame) {
+ if (_decoderType == kVideoDecoderPSX)
+ drawFramePSX(frame);
+ else
+ _vm->_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h);
+ }
if (_decoder->hasDirtyPalette()) {
_decoder->setSystemPalette();
@@ -293,22 +347,44 @@ bool MoviePlayer::playVideo() {
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 false;
+ skipped = true;
_vm->_system->delayMillis(10);
}
- return !_vm->shouldQuit();
+ if (_decoderType == kVideoDecoderPSX) {
+ // Need to jump back to paletted color
+ initGraphics(g_system->getWidth(), g_system->getHeight(), true);
+ }
+
+ return !_vm->shouldQuit() && !skipped;
}
-byte MoviePlayer::findBlackPalIndex() {
+uint32 MoviePlayer::getBlackColor() {
return _black;
}
-byte MoviePlayer::findWhitePalIndex() {
+uint32 MoviePlayer::getWhiteColor() {
return _white;
}
+void MoviePlayer::drawFramePSX(const Graphics::Surface *frame) {
+ // The PSX videos have half resolution
+
+ Graphics::Surface scaledFrame;
+ scaledFrame.create(frame->w, frame->h * 2, frame->format);
+
+ for (int y = 0; y < scaledFrame.h; y++)
+ memcpy(scaledFrame.getBasePtr(0, y), frame->getBasePtr(0, y / 2), scaledFrame.w * scaledFrame.format.bytesPerPixel);
+
+ uint16 x = (g_system->getWidth() - scaledFrame.w) / 2;
+ uint16 y = (g_system->getHeight() - scaledFrame.h) / 2;
+
+ _vm->_system->copyRectToScreen((byte *)scaledFrame.pixels, scaledFrame.pitch, x, y, scaledFrame.w, scaledFrame.h);
+
+ scaledFrame.free();
+}
+
DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle)
: _mixer(mixer), _bgSoundHandle(bgSoundHandle) {
}
@@ -328,6 +404,23 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *
Common::String filename;
Audio::SoundHandle *bgSoundHandle = new Audio::SoundHandle;
+ // For the PSX version, we'll try the PlayStation stream files
+ if (vm->isPsx()) {
+ filename = Common::String(sequenceListPSX[id]) + ".str";
+
+ if (Common::File::exists(filename)) {
+#ifdef USE_RGB_COLOR
+ // All BS1 PSX videos seem to be 15fps
+ Video::VideoDecoder *psxDecoder = new Video::PSXStreamDecoder(15);
+ return new MoviePlayer(vm, textMan, resMan, snd, system, bgSoundHandle, psxDecoder, kVideoDecoderPSX);
+#else
+ GUI::MessageDialog dialog(Common::String::format(_("PSX stream cutscene '%s' cannot be played in paletted mode"), filename.c_str()), _("OK"));
+ dialog.runModal();
+ return 0;
+#endif
+ }
+ }
+
filename = Common::String::format("%s.smk", sequenceList[id]);
if (Common::File::exists(filename)) {
diff --git a/engines/sword1/animation.h b/engines/sword1/animation.h
index 1c03c66..23dae7f 100644
--- a/engines/sword1/animation.h
+++ b/engines/sword1/animation.h
@@ -24,7 +24,6 @@
#define SWORD1_ANIMATION_H
#include "video/dxa_decoder.h"
-#include "video/smk_decoder.h"
#include "video/video_decoder.h"
#include "common/list.h"
@@ -38,7 +37,8 @@ namespace Sword1 {
enum DecoderType {
kVideoDecoderDXA = 0,
- kVideoDecoderSMK = 1
+ kVideoDecoderSMK = 1,
+ kVideoDecoderPSX = 2
};
class MovieText {
@@ -80,7 +80,7 @@ protected:
OSystem *_system;
Common::List<MovieText> _movieTexts;
int _textX, _textY, _textWidth, _textHeight;
- byte _white, _black;
+ uint32 _white, _black;
DecoderType _decoderType;
Video::VideoDecoder *_decoder;
@@ -89,9 +89,10 @@ protected:
bool playVideo();
void performPostProcessing(byte *screen);
+ void drawFramePSX(const Graphics::Surface *frame);
- byte findBlackPalIndex();
- byte findWhitePalIndex();
+ uint32 getBlackColor();
+ uint32 getWhiteColor();
};
MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *resMan, Audio::Mixer *snd, OSystem *system);
diff --git a/engines/sword1/sword1.cpp b/engines/sword1/sword1.cpp
index 865e025..75e8f72 100644
--- a/engines/sword1/sword1.cpp
+++ b/engines/sword1/sword1.cpp
@@ -62,8 +62,9 @@ SwordEngine::SwordEngine(OSystem *syst)
SearchMan.addSubDirectoryMatching(gameDataDir, "speech");
SearchMan.addSubDirectoryMatching(gameDataDir, "video");
SearchMan.addSubDirectoryMatching(gameDataDir, "smackshi");
- SearchMan.addSubDirectoryMatching(gameDataDir, "english");//PSX Demo
- SearchMan.addSubDirectoryMatching(gameDataDir, "italian");//PSX Demo
+ SearchMan.addSubDirectoryMatching(gameDataDir, "streams"); // PSX videos
+ SearchMan.addSubDirectoryMatching(gameDataDir, "english"); // PSX Demo
+ SearchMan.addSubDirectoryMatching(gameDataDir, "italian"); // PSX Demo
_console = new SwordConsole(this);
}
Commit: 8812f885bc95f0e4af05c333780eb77a8c2eaa19
https://github.com/scummvm/scummvm/commit/8812f885bc95f0e4af05c333780eb77a8c2eaa19
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2012-02-23T13:48:18-08:00
Commit Message:
SWORD2: Add support for PSX stream playback
Changed paths:
engines/sword2/animation.cpp
engines/sword2/animation.h
engines/sword2/function.cpp
engines/sword2/sword2.cpp
diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp
index 80b4809..e77ae98 100644
--- a/engines/sword2/animation.cpp
+++ b/engines/sword2/animation.cpp
@@ -40,6 +40,11 @@
#include "gui/message.h"
+#include "video/smk_decoder.h"
+#include "video/psx_decoder.h"
+
+#include "engines/util.h"
+
namespace Sword2 {
///////////////////////////////////////////////////////////////////////////////
@@ -66,6 +71,10 @@ MoviePlayer::~MoviePlayer() {
* @param id the id of the file
*/
bool MoviePlayer::load(const char *name) {
+ // This happens when quitting during the "eye" cutscene.
+ if (_vm->shouldQuit())
+ return false;
+
if (_decoderType == kVideoDecoderDXA)
_bgSoundStream = Audio::SeekableAudioStream::openStreamFile(name);
else
@@ -81,16 +90,26 @@ bool MoviePlayer::load(const char *name) {
case kVideoDecoderSMK:
filename = Common::String::format("%s.smk", name);
break;
+ case kVideoDecoderPSX:
+ filename = Common::String::format("%s.str", name);
+
+ // Need to switch to true color
+ initGraphics(640, 480, true, 0);
+
+ // Need to load here in case it fails in which case we'd need
+ // to go back to paletted mode
+ if (_decoder->loadFile(filename)) {
+ return true;
+ } else {
+ initGraphics(640, 480, true);
+ return false;
+ }
}
return _decoder->loadFile(filename.c_str());
}
void MoviePlayer::play(MovieText *movieTexts, uint32 numMovieTexts, uint32 leadIn, uint32 leadOut) {
- // This happens when quitting during the "eye" cutscene.
- if (_vm->shouldQuit())
- return;
-
_leadOutFrame = _decoder->getFrameCount();
if (_leadOutFrame > 60)
_leadOutFrame -= 60;
@@ -120,6 +139,11 @@ void MoviePlayer::play(MovieText *movieTexts, uint32 numMovieTexts, uint32 leadI
while (_snd->isSoundHandleActive(*_bgSoundHandle))
_system->delayMillis(100);
+
+ if (_decoderType == kVideoDecoderPSX) {
+ // Need to jump back to paletted color
+ initGraphics(640, 480, true);
+ }
}
void MoviePlayer::openTextObject(uint32 index) {
@@ -165,7 +189,7 @@ void MoviePlayer::openTextObject(uint32 index) {
}
}
-void MoviePlayer::closeTextObject(uint32 index, byte *screen, uint16 pitch) {
+void MoviePlayer::closeTextObject(uint32 index, Graphics::Surface *screen, uint16 pitch) {
if (index < _numMovieTexts) {
MovieText *text = &_movieTexts[index];
@@ -180,23 +204,23 @@ void MoviePlayer::closeTextObject(uint32 index, byte *screen, uint16 pitch) {
int frameWidth = _decoder->getWidth();
int frameHeight = _decoder->getHeight();
+
+ if (_decoderType == kVideoDecoderPSX)
+ frameHeight *= 2;
+
int frameX = (_system->getWidth() - frameWidth) / 2;
int frameY = (_system->getHeight() - frameHeight) / 2;
- byte black = findBlackPalIndex();
-
- byte *dst = screen + _textY * pitch;
+ uint32 black = getBlackColor();
for (int y = 0; y < text->_textSprite.h; y++) {
if (_textY + y < frameY || _textY + y >= frameY + frameHeight) {
- memset(dst + _textX, black, text->_textSprite.w);
+ screen->hLine(_textX, _textY + y, _textX + text->_textSprite.w, black);
} else {
if (frameX > _textX)
- memset(dst + _textX, black, frameX - _textX);
+ screen->hLine(_textX, _textY + y, frameX, black);
if (frameX + frameWidth < _textX + text->_textSprite.w)
- memset(dst + frameX + frameWidth, black, _textX + text->_textSprite.w - (frameX + frameWidth));
+ screen->hLine(frameX + frameWidth, _textY + y, text->_textSprite.w, black);
}
-
- dst += pitch;
}
}
@@ -206,11 +230,24 @@ void MoviePlayer::closeTextObject(uint32 index, byte *screen, uint16 pitch) {
}
}
-void MoviePlayer::drawTextObject(uint32 index, byte *screen, uint16 pitch) {
+#define PUT_PIXEL(c) \
+ switch (screen->format.bytesPerPixel) { \
+ case 1: \
+ *dst = (c); \
+ break; \
+ case 2: \
+ WRITE_UINT16(dst, (c)); \
+ break; \
+ case 4: \
+ WRITE_UINT32(dst, (c)); \
+ break; \
+ }
+
+void MoviePlayer::drawTextObject(uint32 index, Graphics::Surface *screen, uint16 pitch) {
MovieText *text = &_movieTexts[index];
- byte white = findWhitePalIndex();
- byte black = findBlackPalIndex();
+ uint32 white = getWhiteColor();
+ uint32 black = getBlackColor();
if (text->_textMem && _textSurface) {
byte *src = text->_textSprite.data;
@@ -226,17 +263,20 @@ void MoviePlayer::drawTextObject(uint32 index, byte *screen, uint16 pitch) {
src = psxSpriteBuffer;
}
- byte *dst = screen + _textY * pitch + _textX;
-
for (int y = 0; y < height; y++) {
+ byte *dst = (byte *)screen->getBasePtr(_textX, _textY + y);
+
for (int x = 0; x < width; x++) {
- if (src[x] == 1)
- dst[x] = black;
- else if (src[x] == 255)
- dst[x] = white;
+ if (src[x] == 1) {
+ PUT_PIXEL(black);
+ } else if (src[x] == 255) {
+ PUT_PIXEL(white);
+ }
+
+ dst += screen->format.bytesPerPixel;
}
+
src += width;
- dst += pitch;
}
// Free buffer used to resize psx sprite
@@ -245,7 +285,9 @@ void MoviePlayer::drawTextObject(uint32 index, byte *screen, uint16 pitch) {
}
}
-void MoviePlayer::performPostProcessing(byte *screen, uint16 pitch) {
+#undef PUT_PIXEL
+
+void MoviePlayer::performPostProcessing(Graphics::Surface *screen, uint16 pitch) {
MovieText *text;
int frame = _decoder->getCurFrame();
@@ -286,8 +328,12 @@ bool MoviePlayer::playVideo() {
while (!_vm->shouldQuit() && !_decoder->endOfVideo()) {
if (_decoder->needsUpdate()) {
const Graphics::Surface *frame = _decoder->decodeNextFrame();
- if (frame)
- _vm->_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h);
+ if (frame) {
+ if (_decoderType == kVideoDecoderPSX)
+ drawFramePSX(frame);
+ else
+ _vm->_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h);
+ }
if (_decoder->hasDirtyPalette()) {
_decoder->setSystemPalette();
@@ -319,7 +365,7 @@ bool MoviePlayer::playVideo() {
}
Graphics::Surface *screen = _vm->_system->lockScreen();
- performPostProcessing((byte *)screen->pixels, screen->pitch);
+ performPostProcessing(screen, screen->pitch);
_vm->_system->unlockScreen();
_vm->_system->updateScreen();
}
@@ -335,12 +381,29 @@ bool MoviePlayer::playVideo() {
return !_vm->shouldQuit();
}
-byte MoviePlayer::findBlackPalIndex() {
- return _black;
+uint32 MoviePlayer::getBlackColor() {
+ return (_decoderType == kVideoDecoderPSX) ? g_system->getScreenFormat().RGBToColor(0x00, 0x00, 0x00) : _black;
}
-byte MoviePlayer::findWhitePalIndex() {
- return _white;
+uint32 MoviePlayer::getWhiteColor() {
+ return (_decoderType == kVideoDecoderPSX) ? g_system->getScreenFormat().RGBToColor(0xFF, 0xFF, 0xFF) : _white;
+}
+
+void MoviePlayer::drawFramePSX(const Graphics::Surface *frame) {
+ // The PSX videos have half resolution
+
+ Graphics::Surface scaledFrame;
+ scaledFrame.create(frame->w, frame->h * 2, frame->format);
+
+ for (int y = 0; y < scaledFrame.h; y++)
+ memcpy(scaledFrame.getBasePtr(0, y), frame->getBasePtr(0, y / 2), scaledFrame.w * scaledFrame.format.bytesPerPixel);
+
+ uint16 x = (g_system->getWidth() - scaledFrame.w) / 2;
+ uint16 y = (g_system->getHeight() - scaledFrame.h) / 2;
+
+ _vm->_system->copyRectToScreen((byte *)scaledFrame.pixels, scaledFrame.pitch, x, y, scaledFrame.w, scaledFrame.h);
+
+ scaledFrame.free();
}
DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle)
@@ -358,10 +421,23 @@ uint32 DXADecoderWithSound::getElapsedTime() const {
// Factory function for creating the appropriate cutscene player
///////////////////////////////////////////////////////////////////////////////
-MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, Audio::Mixer *snd, OSystem *system) {
+MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, uint32 frameCount) {
Common::String filename;
Audio::SoundHandle *bgSoundHandle = new Audio::SoundHandle;
+ filename = Common::String::format("%s.str", name);
+
+ if (Common::File::exists(filename)) {
+#ifdef USE_RGB_COLOR
+ Video::VideoDecoder *psxDecoder = new Video::PSXStreamDecoder(Video::PSXStreamDecoder::kCD2x, frameCount);
+ return new MoviePlayer(vm, snd, system, bgSoundHandle, psxDecoder, kVideoDecoderPSX);
+#else
+ GUI::MessageDialog dialog(_("PSX cutscenes found but ScummVM has been built without RGB color support"), _("OK"));
+ dialog.runModal();
+ return NULL;
+#endif
+ }
+
filename = Common::String::format("%s.smk", name);
if (Common::File::exists(filename)) {
diff --git a/engines/sword2/animation.h b/engines/sword2/animation.h
index 1f5fced..3ef8dac 100644
--- a/engines/sword2/animation.h
+++ b/engines/sword2/animation.h
@@ -26,7 +26,6 @@
#define SWORD2_ANIMATION_H
#include "video/dxa_decoder.h"
-#include "video/smk_decoder.h"
#include "video/video_decoder.h"
#include "audio/mixer.h"
@@ -36,7 +35,8 @@ namespace Sword2 {
enum DecoderType {
kVideoDecoderDXA = 0,
- kVideoDecoderSMK = 1
+ kVideoDecoderSMK = 1,
+ kVideoDecoderPSX = 2
};
struct MovieText {
@@ -93,18 +93,19 @@ protected:
uint32 _leadOut;
int _leadOutFrame;
- void performPostProcessing(byte *screen, uint16 pitch);
+ void performPostProcessing(Graphics::Surface *screen, uint16 pitch);
bool playVideo();
+ void drawFramePSX(const Graphics::Surface *frame);
void openTextObject(uint32 index);
- void closeTextObject(uint32 index, byte *screen, uint16 pitch);
- void drawTextObject(uint32 index, byte *screen, uint16 pitch);
+ void closeTextObject(uint32 index, Graphics::Surface *screen, uint16 pitch);
+ void drawTextObject(uint32 index, Graphics::Surface *screen, uint16 pitch);
- byte findBlackPalIndex();
- byte findWhitePalIndex();
+ uint32 getBlackColor();
+ uint32 getWhiteColor();
};
-MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, Audio::Mixer *snd, OSystem *system);
+MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, uint32 frameCount);
} // End of namespace Sword2
diff --git a/engines/sword2/function.cpp b/engines/sword2/function.cpp
index 60ee617..836b252 100644
--- a/engines/sword2/function.cpp
+++ b/engines/sword2/function.cpp
@@ -2137,7 +2137,9 @@ int32 Logic::fnPlaySequence(int32 *params) {
// pause sfx during sequence
_vm->_sound->pauseFx();
- _moviePlayer = makeMoviePlayer(filename, _vm, _vm->_mixer, _vm->_system);
+ uint32 frameCount = Sword2Engine::isPsx() ? params[1] : 0;
+
+ _moviePlayer = makeMoviePlayer(filename, _vm, _vm->_mixer, _vm->_system, frameCount);
if (_moviePlayer && _moviePlayer->load(filename)) {
_moviePlayer->play(_sequenceTextList, _sequenceTextLines, _smackerLeadIn, _smackerLeadOut);
diff --git a/engines/sword2/sword2.cpp b/engines/sword2/sword2.cpp
index 3b79652..bdfc388 100644
--- a/engines/sword2/sword2.cpp
+++ b/engines/sword2/sword2.cpp
@@ -255,6 +255,7 @@ Sword2Engine::Sword2Engine(OSystem *syst) : Engine(syst), _rnd("sword2") {
SearchMan.addSubDirectoryMatching(gameDataDir, "sword2");
SearchMan.addSubDirectoryMatching(gameDataDir, "video");
SearchMan.addSubDirectoryMatching(gameDataDir, "smacks");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "streams"); // PSX video
if (!scumm_stricmp(ConfMan.get("gameid").c_str(), "sword2demo") || !scumm_stricmp(ConfMan.get("gameid").c_str(), "sword2psxdemo"))
_features = GF_DEMO;
Commit: ee35d32a362d58891fedff9843867397f2d4497b
https://github.com/scummvm/scummvm/commit/ee35d32a362d58891fedff9843867397f2d4497b
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2012-02-23T13:48:18-08:00
Commit Message:
VIDEO: Implement PSX stream v3 frame support
Changed paths:
video/psx_decoder.cpp
video/psx_decoder.h
diff --git a/video/psx_decoder.cpp b/video/psx_decoder.cpp
index 4ed5a16..a0705e8 100644
--- a/video/psx_decoder.cpp
+++ b/video/psx_decoder.cpp
@@ -58,17 +58,53 @@ PSXStreamDecoder::PSXStreamDecoder(CDSpeed speed, uint32 frameCount) {
PSXStreamDecoder::~PSXStreamDecoder() {
close();
delete _surface;
- delete _huffman;
+ delete _acHuffman;
+ delete _dcHuffmanLuma;
+ delete _dcHuffmanChroma;
}
-#define CODE_COUNT 113
-#define HUFFVAL(z, a) ((z << 8) | a)
+// Here are the codes/lengths/symbols that are used for decoding
+// DC coefficients (version 3 frames only)
+
+#define DC_CODE_COUNT 9
+#define DC_HUFF_VAL(b, n, p) (((b) << 16) | ((n) << 8) | (p))
+#define GET_DC_BITS(x) ((x) >> 16)
+#define GET_DC_NEG(x) ((int)(((x) >> 8) & 0xff))
+#define GET_DC_POS(x) ((int)((x) & 0xff))
+
+static const uint32 s_huffmanDCChromaCodes[DC_CODE_COUNT] = {
+ 254, 126, 62, 30, 14, 6, 2, 1, 0
+};
+
+static const byte s_huffmanDCChromaLengths[DC_CODE_COUNT] = {
+ 8, 7, 6, 5, 4, 3, 2, 2, 2
+};
+
+static const uint32 s_huffmanDCLumaCodes[DC_CODE_COUNT] = {
+ 126, 62, 30, 14, 6, 5, 1, 0, 4
+};
+
+static const byte s_huffmanDCLumaLengths[DC_CODE_COUNT] = {
+ 7, 6, 5, 4, 3, 3, 2, 2, 3
+};
+
+static const uint32 s_huffmanDCSymbols[DC_CODE_COUNT] = {
+ DC_HUFF_VAL(8, 255, 128), DC_HUFF_VAL(7, 127, 64), DC_HUFF_VAL(6, 63, 32),
+ DC_HUFF_VAL(5, 31, 16), DC_HUFF_VAL(4, 15, 8), DC_HUFF_VAL(3, 7, 4),
+ DC_HUFF_VAL(2, 3, 2), DC_HUFF_VAL(1, 1, 1), DC_HUFF_VAL(0, 0, 0)
+};
+
+// Here are the codes/lengths/symbols that are used for decoding
+// DC coefficients (version 2 and 3 frames)
+
+#define AC_CODE_COUNT 113
+#define AC_HUFF_VAL(z, a) ((z << 8) | a)
#define ESCAPE_CODE ((uint32)-1) // arbitrary, just so we can tell what code it is
#define END_OF_BLOCK ((uint32)-2) // arbitrary, just so we can tell what code it is
-#define GET_ZEROES(code) (code >> 8)
-#define GET_AC(code) ((int)(code & 0xff))
+#define GET_AC_ZERO_RUN(code) (code >> 8)
+#define GET_AC_COEFFICIENT(code) ((int)(code & 0xff))
-static const uint32 s_huffmanCodes[CODE_COUNT] = {
+static const uint32 s_huffmanACCodes[AC_CODE_COUNT] = {
// Regular codes
3, 3, 4, 5, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7,
32, 33, 34, 35, 36, 37, 38, 39, 8, 9, 10, 11,
@@ -87,7 +123,7 @@ static const uint32 s_huffmanCodes[CODE_COUNT] = {
2
};
-static const byte s_huffmanLengths[CODE_COUNT] = {
+static const byte s_huffmanACLengths[AC_CODE_COUNT] = {
// Regular codes
2, 3, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10,
@@ -106,31 +142,31 @@ static const byte s_huffmanLengths[CODE_COUNT] = {
2
};
-static const uint32 s_huffmanSymbols[CODE_COUNT] = {
+static const uint32 s_huffmanACSymbols[AC_CODE_COUNT] = {
// Regular codes
- HUFFVAL(0, 1), HUFFVAL(1, 1), HUFFVAL(0, 2), HUFFVAL(2, 1), HUFFVAL(0, 3),
- HUFFVAL(4, 1), HUFFVAL(3, 1), HUFFVAL(7, 1), HUFFVAL(6, 1), HUFFVAL(1, 2),
- HUFFVAL(5, 1), HUFFVAL(2, 2), HUFFVAL(9, 1), HUFFVAL(0, 4), HUFFVAL(8, 1),
- HUFFVAL(13, 1), HUFFVAL(0, 6), HUFFVAL(12, 1), HUFFVAL(11, 1), HUFFVAL(3, 2),
- HUFFVAL(1, 3), HUFFVAL(0, 5), HUFFVAL(10, 1), HUFFVAL(16, 1), HUFFVAL(5, 2),
- HUFFVAL(0, 7), HUFFVAL(2, 3), HUFFVAL(1, 4), HUFFVAL(15, 1), HUFFVAL(14, 1),
- HUFFVAL(4, 2), HUFFVAL(0, 11), HUFFVAL(8, 2), HUFFVAL(4, 3), HUFFVAL(0, 10),
- HUFFVAL(2, 4), HUFFVAL(7, 2), HUFFVAL(21, 1), HUFFVAL(20, 1), HUFFVAL(0, 9),
- HUFFVAL(19, 1), HUFFVAL(18, 1), HUFFVAL(1, 5), HUFFVAL(3, 3), HUFFVAL(0, 8),
- HUFFVAL(6, 2), HUFFVAL(17, 1), HUFFVAL(10, 2), HUFFVAL(9, 2), HUFFVAL(5, 3),
- HUFFVAL(3, 4), HUFFVAL(2, 5), HUFFVAL(1, 7), HUFFVAL(1, 6), HUFFVAL(0, 15),
- HUFFVAL(0, 14), HUFFVAL(0, 13), HUFFVAL(0, 12), HUFFVAL(26, 1), HUFFVAL(25, 1),
- HUFFVAL(24, 1), HUFFVAL(23, 1), HUFFVAL(22, 1), HUFFVAL(0, 31), HUFFVAL(0, 30),
- HUFFVAL(0, 29), HUFFVAL(0, 28), HUFFVAL(0, 27), HUFFVAL(0, 26), HUFFVAL(0, 25),
- HUFFVAL(0, 24), HUFFVAL(0, 23), HUFFVAL(0, 22), HUFFVAL(0, 21), HUFFVAL(0, 20),
- HUFFVAL(0, 19), HUFFVAL(0, 18), HUFFVAL(0, 17), HUFFVAL(0, 16), HUFFVAL(0, 40),
- HUFFVAL(0, 39), HUFFVAL(0, 38), HUFFVAL(0, 37), HUFFVAL(0, 36), HUFFVAL(0, 35),
- HUFFVAL(0, 34), HUFFVAL(0, 33), HUFFVAL(0, 32), HUFFVAL(1, 14), HUFFVAL(1, 13),
- HUFFVAL(1, 12), HUFFVAL(1, 11), HUFFVAL(1, 10), HUFFVAL(1, 9), HUFFVAL(1, 8),
- HUFFVAL(1, 18), HUFFVAL(1, 17), HUFFVAL(1, 16), HUFFVAL(1, 15), HUFFVAL(6, 3),
- HUFFVAL(16, 2), HUFFVAL(15, 2), HUFFVAL(14, 2), HUFFVAL(13, 2), HUFFVAL(12, 2),
- HUFFVAL(11, 2), HUFFVAL(31, 1), HUFFVAL(30, 1), HUFFVAL(29, 1), HUFFVAL(28, 1),
- HUFFVAL(27, 1),
+ AC_HUFF_VAL(0, 1), AC_HUFF_VAL(1, 1), AC_HUFF_VAL(0, 2), AC_HUFF_VAL(2, 1), AC_HUFF_VAL(0, 3),
+ AC_HUFF_VAL(4, 1), AC_HUFF_VAL(3, 1), AC_HUFF_VAL(7, 1), AC_HUFF_VAL(6, 1), AC_HUFF_VAL(1, 2),
+ AC_HUFF_VAL(5, 1), AC_HUFF_VAL(2, 2), AC_HUFF_VAL(9, 1), AC_HUFF_VAL(0, 4), AC_HUFF_VAL(8, 1),
+ AC_HUFF_VAL(13, 1), AC_HUFF_VAL(0, 6), AC_HUFF_VAL(12, 1), AC_HUFF_VAL(11, 1), AC_HUFF_VAL(3, 2),
+ AC_HUFF_VAL(1, 3), AC_HUFF_VAL(0, 5), AC_HUFF_VAL(10, 1), AC_HUFF_VAL(16, 1), AC_HUFF_VAL(5, 2),
+ AC_HUFF_VAL(0, 7), AC_HUFF_VAL(2, 3), AC_HUFF_VAL(1, 4), AC_HUFF_VAL(15, 1), AC_HUFF_VAL(14, 1),
+ AC_HUFF_VAL(4, 2), AC_HUFF_VAL(0, 11), AC_HUFF_VAL(8, 2), AC_HUFF_VAL(4, 3), AC_HUFF_VAL(0, 10),
+ AC_HUFF_VAL(2, 4), AC_HUFF_VAL(7, 2), AC_HUFF_VAL(21, 1), AC_HUFF_VAL(20, 1), AC_HUFF_VAL(0, 9),
+ AC_HUFF_VAL(19, 1), AC_HUFF_VAL(18, 1), AC_HUFF_VAL(1, 5), AC_HUFF_VAL(3, 3), AC_HUFF_VAL(0, 8),
+ AC_HUFF_VAL(6, 2), AC_HUFF_VAL(17, 1), AC_HUFF_VAL(10, 2), AC_HUFF_VAL(9, 2), AC_HUFF_VAL(5, 3),
+ AC_HUFF_VAL(3, 4), AC_HUFF_VAL(2, 5), AC_HUFF_VAL(1, 7), AC_HUFF_VAL(1, 6), AC_HUFF_VAL(0, 15),
+ AC_HUFF_VAL(0, 14), AC_HUFF_VAL(0, 13), AC_HUFF_VAL(0, 12), AC_HUFF_VAL(26, 1), AC_HUFF_VAL(25, 1),
+ AC_HUFF_VAL(24, 1), AC_HUFF_VAL(23, 1), AC_HUFF_VAL(22, 1), AC_HUFF_VAL(0, 31), AC_HUFF_VAL(0, 30),
+ AC_HUFF_VAL(0, 29), AC_HUFF_VAL(0, 28), AC_HUFF_VAL(0, 27), AC_HUFF_VAL(0, 26), AC_HUFF_VAL(0, 25),
+ AC_HUFF_VAL(0, 24), AC_HUFF_VAL(0, 23), AC_HUFF_VAL(0, 22), AC_HUFF_VAL(0, 21), AC_HUFF_VAL(0, 20),
+ AC_HUFF_VAL(0, 19), AC_HUFF_VAL(0, 18), AC_HUFF_VAL(0, 17), AC_HUFF_VAL(0, 16), AC_HUFF_VAL(0, 40),
+ AC_HUFF_VAL(0, 39), AC_HUFF_VAL(0, 38), AC_HUFF_VAL(0, 37), AC_HUFF_VAL(0, 36), AC_HUFF_VAL(0, 35),
+ AC_HUFF_VAL(0, 34), AC_HUFF_VAL(0, 33), AC_HUFF_VAL(0, 32), AC_HUFF_VAL(1, 14), AC_HUFF_VAL(1, 13),
+ AC_HUFF_VAL(1, 12), AC_HUFF_VAL(1, 11), AC_HUFF_VAL(1, 10), AC_HUFF_VAL(1, 9), AC_HUFF_VAL(1, 8),
+ AC_HUFF_VAL(1, 18), AC_HUFF_VAL(1, 17), AC_HUFF_VAL(1, 16), AC_HUFF_VAL(1, 15), AC_HUFF_VAL(6, 3),
+ AC_HUFF_VAL(16, 2), AC_HUFF_VAL(15, 2), AC_HUFF_VAL(14, 2), AC_HUFF_VAL(13, 2), AC_HUFF_VAL(12, 2),
+ AC_HUFF_VAL(11, 2), AC_HUFF_VAL(31, 1), AC_HUFF_VAL(30, 1), AC_HUFF_VAL(29, 1), AC_HUFF_VAL(28, 1),
+ AC_HUFF_VAL(27, 1),
// Escape code
ESCAPE_CODE,
@@ -143,7 +179,9 @@ void PSXStreamDecoder::initCommon() {
_audStream = 0;
_surface = new Graphics::Surface();
_yBuffer = _cbBuffer = _crBuffer = 0;
- _huffman = new Common::Huffman(0, CODE_COUNT, s_huffmanCodes, s_huffmanLengths, s_huffmanSymbols);
+ _acHuffman = new Common::Huffman(0, AC_CODE_COUNT, s_huffmanACCodes, s_huffmanACLengths, s_huffmanACSymbols);
+ _dcHuffmanChroma = new Common::Huffman(0, DC_CODE_COUNT, s_huffmanDCChromaCodes, s_huffmanDCChromaLengths, s_huffmanDCSymbols);
+ _dcHuffmanLuma = new Common::Huffman(0, DC_CODE_COUNT, s_huffmanDCLumaCodes, s_huffmanDCLumaLengths, s_huffmanDCSymbols);
}
#define RAW_CD_SECTOR_SIZE 2352
@@ -448,6 +486,9 @@ void PSXStreamDecoder::decodeFrame(Common::SeekableReadStream *frame) {
if (version != 2 && version != 3)
error("Unknown PSX stream frame version");
+ // Initalize default v3 DC here
+ _lastDC[0] = _lastDC[1] = _lastDC[2] = 0;
+
for (int mbX = 0; mbX < _macroBlocksW; mbX++)
for (int mbY = 0; mbY < _macroBlocksH; mbY++)
decodeMacroBlock(&bits, mbX, mbY, scale, version);
@@ -461,12 +502,12 @@ void PSXStreamDecoder::decodeMacroBlock(Common::BitStream *bits, int mbX, int mb
int pitchC = _macroBlocksW * 8;
// Note the strange order of red before blue
- decodeBlock(bits, _crBuffer + (mbY * pitchC + mbX) * 8, pitchC, scale, version);
- decodeBlock(bits, _cbBuffer + (mbY * pitchC + mbX) * 8, pitchC, scale, version);
- decodeBlock(bits, _yBuffer + (mbY * pitchY + mbX) * 16, pitchY, scale, version);
- decodeBlock(bits, _yBuffer + (mbY * pitchY + mbX) * 16 + 8, pitchY, scale, version);
- decodeBlock(bits, _yBuffer + (mbY * pitchY + mbX) * 16 + 8 * pitchY, pitchY, scale, version);
- decodeBlock(bits, _yBuffer + (mbY * pitchY + mbX) * 16 + 8 * pitchY + 8, pitchY, scale, version);
+ decodeBlock(bits, _crBuffer + (mbY * pitchC + mbX) * 8, pitchC, scale, version, kPlaneV);
+ decodeBlock(bits, _cbBuffer + (mbY * pitchC + mbX) * 8, pitchC, scale, version, kPlaneU);
+ decodeBlock(bits, _yBuffer + (mbY * pitchY + mbX) * 16, pitchY, scale, version, kPlaneY);
+ decodeBlock(bits, _yBuffer + (mbY * pitchY + mbX) * 16 + 8, pitchY, scale, version, kPlaneY);
+ decodeBlock(bits, _yBuffer + (mbY * pitchY + mbX) * 16 + 8 * pitchY, pitchY, scale, version, kPlaneY);
+ decodeBlock(bits, _yBuffer + (mbY * pitchY + mbX) * 16 + 8 * pitchY + 8, pitchY, scale, version, kPlaneY);
}
// Standard JPEG/MPEG zig zag table
@@ -503,6 +544,32 @@ void PSXStreamDecoder::dequantizeBlock(int *coefficients, float *block, uint16 s
}
}
+int PSXStreamDecoder::readDC(Common::BitStream *bits, uint16 version, PlaneType plane) {
+ // Version 2 just has its coefficient as 10-bits
+ if (version == 2)
+ return readSignedCoefficient(bits);
+
+ // Version 3 has it stored as huffman codes as a difference from the previous DC value
+
+ Common::Huffman *huffman = (plane == kPlaneY) ? _dcHuffmanLuma : _dcHuffmanChroma;
+
+ uint32 symbol = huffman->getSymbol(*bits);
+ int dc = 0;
+
+ if (GET_DC_BITS(symbol) != 0) {
+ bool negative = (bits->getBit() == 0);
+ dc = bits->getBits(GET_DC_BITS(symbol) - 1);
+
+ if (negative)
+ dc -= GET_DC_NEG(symbol);
+ else
+ dc += GET_DC_POS(symbol);
+ }
+
+ _lastDC[plane] += dc * 4; // convert from 8-bit to 10-bit
+ return _lastDC[plane];
+}
+
#define BLOCK_OVERFLOW_CHECK() \
if (count > 63) \
error("PSXStreamDecoder::readAC(): Too many coefficients")
@@ -515,7 +582,7 @@ void PSXStreamDecoder::readAC(Common::BitStream *bits, int *block) {
int count = 0;
while (!bits->eos()) {
- uint32 symbol = _huffman->getSymbol(*bits);
+ uint32 symbol = _acHuffman->getSymbol(*bits);
if (symbol == ESCAPE_CODE) {
// The escape code!
@@ -529,15 +596,15 @@ void PSXStreamDecoder::readAC(Common::BitStream *bits, int *block) {
break;
} else {
// Normal huffman code
- int zeroes = GET_ZEROES(symbol);
+ int zeroes = GET_AC_ZERO_RUN(symbol);
count += zeroes + 1;
BLOCK_OVERFLOW_CHECK();
block += zeroes;
if (bits->getBit())
- *block++ = -GET_AC(symbol);
+ *block++ = -GET_AC_COEFFICIENT(symbol);
else
- *block++ = GET_AC(symbol);
+ *block++ = GET_AC_COEFFICIENT(symbol);
}
}
}
@@ -603,18 +670,11 @@ void PSXStreamDecoder::idct(float *dequantData, float *result) {
}
}
-void PSXStreamDecoder::decodeBlock(Common::BitStream *bits, byte *block, int pitch, uint16 scale, uint16 version) {
- int dc;
-
- if (version == 2) {
- dc = readSignedCoefficient(bits);
- } else {
- // TODO
- error("Unhandled PSX stream version 3 DC");
- }
-
+void PSXStreamDecoder::decodeBlock(Common::BitStream *bits, byte *block, int pitch, uint16 scale, uint16 version, PlaneType plane) {
+ // Version 2 just has signed 10 bits for DC
+ // Version 3 has them huffman coded
int coefficients[8 * 8];
- coefficients[0] = dc; // Start us off with the DC
+ coefficients[0] = readDC(bits, version, plane);
readAC(bits, &coefficients[1]); // Read in the AC
// Dequantize
diff --git a/video/psx_decoder.h b/video/psx_decoder.h
index e8de507..4223f03 100644
--- a/video/psx_decoder.h
+++ b/video/psx_decoder.h
@@ -96,15 +96,26 @@ private:
Audio::QueuingAudioStream *_audStream;
void queueAudioFromSector(Common::SeekableReadStream *sector);
- Common::Huffman *_huffman;
+ enum PlaneType {
+ kPlaneY = 0,
+ kPlaneU = 1,
+ kPlaneV = 2
+ };
+
uint16 _macroBlocksW, _macroBlocksH;
byte *_yBuffer, *_cbBuffer, *_crBuffer;
void decodeFrame(Common::SeekableReadStream *frame);
void decodeMacroBlock(Common::BitStream *bits, int mbX, int mbY, uint16 scale, uint16 version);
- void decodeBlock(Common::BitStream *bits, byte *block, int pitch, uint16 scale, uint16 version);
+ void decodeBlock(Common::BitStream *bits, byte *block, int pitch, uint16 scale, uint16 version, PlaneType plane);
- void dequantizeBlock(int *coefficients, float *block, uint16 scale);
void readAC(Common::BitStream *bits, int *block);
+ Common::Huffman *_acHuffman;
+
+ int readDC(Common::BitStream *bits, uint16 version, PlaneType plane);
+ Common::Huffman *_dcHuffmanLuma, *_dcHuffmanChroma;
+ int _lastDC[3];
+
+ void dequantizeBlock(int *coefficients, float *block, uint16 scale);
void idct(float *dequantData, float *result);
int readSignedCoefficient(Common::BitStream *bits);
Commit: 66cd8bdd68d9e0d14e40c9f55c06f8ea9cf2006b
https://github.com/scummvm/scummvm/commit/66cd8bdd68d9e0d14e40c9f55c06f8ea9cf2006b
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2012-02-23T13:48:18-08:00
Commit Message:
VIDEO: Make PSX streams calculate frame timing solely from CD speed
BS2 videos now play at the proper rate and BS1 videos have improved a/v sync.
Changed paths:
engines/sword1/animation.cpp
video/psx_decoder.cpp
video/psx_decoder.h
diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp
index 9e190e0..a1ace0f 100644
--- a/engines/sword1/animation.cpp
+++ b/engines/sword1/animation.cpp
@@ -410,8 +410,8 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *
if (Common::File::exists(filename)) {
#ifdef USE_RGB_COLOR
- // All BS1 PSX videos seem to be 15fps
- Video::VideoDecoder *psxDecoder = new Video::PSXStreamDecoder(15);
+ // All BS1 PSX videos run the videos at 2x speed
+ Video::VideoDecoder *psxDecoder = new Video::PSXStreamDecoder(Video::PSXStreamDecoder::kCD2x);
return new MoviePlayer(vm, textMan, resMan, snd, system, bgSoundHandle, psxDecoder, kVideoDecoderPSX);
#else
GUI::MessageDialog dialog(Common::String::format(_("PSX stream cutscene '%s' cannot be played in paletted mode"), filename.c_str()), _("OK"));
diff --git a/video/psx_decoder.cpp b/video/psx_decoder.cpp
index a0705e8..7c04b7f 100644
--- a/video/psx_decoder.cpp
+++ b/video/psx_decoder.cpp
@@ -38,31 +38,6 @@
namespace Video {
-PSXStreamDecoder::PSXStreamDecoder(Common::Rational frameRate) {
- assert(frameRate != 0);
- initCommon();
- _frameRate = frameRate;
- _frameCount = 0;
- _speed = kCDUnk;
-}
-
-PSXStreamDecoder::PSXStreamDecoder(CDSpeed speed, uint32 frameCount) {
- assert(speed != kCDUnk);
- assert(frameCount != 0);
- initCommon();
- _frameCount = frameCount;
- _speed = speed;
- // frame rate will be calculated in loadStream()
-}
-
-PSXStreamDecoder::~PSXStreamDecoder() {
- close();
- delete _surface;
- delete _acHuffman;
- delete _dcHuffmanLuma;
- delete _dcHuffmanChroma;
-}
-
// Here are the codes/lengths/symbols that are used for decoding
// DC coefficients (version 3 frames only)
@@ -174,7 +149,7 @@ static const uint32 s_huffmanACSymbols[AC_CODE_COUNT] = {
END_OF_BLOCK
};
-void PSXStreamDecoder::initCommon() {
+PSXStreamDecoder::PSXStreamDecoder(CDSpeed speed, uint32 frameCount) : _nextFrameStartTime(0, speed), _frameCount(frameCount) {
_stream = 0;
_audStream = 0;
_surface = new Graphics::Surface();
@@ -184,6 +159,14 @@ void PSXStreamDecoder::initCommon() {
_dcHuffmanLuma = new Common::Huffman(0, DC_CODE_COUNT, s_huffmanDCLumaCodes, s_huffmanDCLumaLengths, s_huffmanDCSymbols);
}
+PSXStreamDecoder::~PSXStreamDecoder() {
+ close();
+ delete _surface;
+ delete _acHuffman;
+ delete _dcHuffmanLuma;
+ delete _dcHuffmanChroma;
+}
+
#define RAW_CD_SECTOR_SIZE 2352
#define CDXA_TYPE_MASK 0x0E
@@ -227,14 +210,6 @@ bool PSXStreamDecoder::loadStream(Common::SeekableReadStream *stream) {
delete sector;
_stream->seek(0);
- // Calculate frame rate based on CD speed
- if (_speed != kCDUnk) {
- // TODO: This algorithm is too basic and not accurate enough
- // TODO: Count the number of sectors per frame to get a better estimate
- _frameRate = Common::Rational(_speed * _frameCount, _stream->size() / RAW_CD_SECTOR_SIZE);
- _frameRate.debugPrint(0, "Approximate PSX Stream Frame Rate:");
- }
-
return true;
}
@@ -267,7 +242,20 @@ uint32 PSXStreamDecoder::getElapsedTime() const {
//if (_audStream)
// return _mixer->getSoundElapsedTime(_audHandle);
- return FixedRateVideoDecoder::getElapsedTime();
+ return VideoDecoder::getElapsedTime();
+}
+
+uint32 PSXStreamDecoder::getTimeToNextFrame() const {
+ if (!isVideoLoaded() || endOfVideo())
+ return 0;
+
+ uint32 nextTimeMillis = _nextFrameStartTime.msecs();
+ uint32 elapsedTime = getElapsedTime();
+
+ if (elapsedTime > nextTimeMillis)
+ return 0;
+
+ return nextTimeMillis - elapsedTime;
}
#define VIDEO_DATA_CHUNK_SIZE 2016
@@ -276,9 +264,11 @@ uint32 PSXStreamDecoder::getElapsedTime() const {
const Graphics::Surface *PSXStreamDecoder::decodeNextFrame() {
Common::SeekableReadStream *sector = 0;
byte *partialFrame = 0;
+ int sectorsRead = 0;
while (!endOfVideo()) {
sector = readSector();
+ sectorsRead++;
if (!sector)
error("Corrupt PSX stream sector");
@@ -322,6 +312,15 @@ const Graphics::Surface *PSXStreamDecoder::decodeNextFrame() {
if (_curFrame == 0)
_startTime = g_system->getMillis();
+ // Increase the time by the amount of sectors we read
+ // One may notice that this is still not the most precise
+ // method since a frame takes up the time its sectors took
+ // up instead of the amount of time it takes the next frame
+ // to be read from the sectors. The actual frame rate should
+ // be constant instead of variable, so the slight difference
+ // in a frame's showing time is negligible (1/150 of a second).
+ _nextFrameStartTime = _nextFrameStartTime.addFrames(sectorsRead);
+
return _surface;
}
} else
diff --git a/video/psx_decoder.h b/video/psx_decoder.h
index 4223f03..6218704 100644
--- a/video/psx_decoder.h
+++ b/video/psx_decoder.h
@@ -53,18 +53,16 @@ namespace Video {
* - sword1 (psx)
* - sword2 (psx)
*/
-class PSXStreamDecoder : public FixedRateVideoDecoder {
+class PSXStreamDecoder : public VideoDecoder {
public:
// CD speed in sectors/second
// Calling code should use these enum values instead of the constants
enum CDSpeed {
- kCDUnk = 0,
kCD1x = 75,
kCD2x = 150
};
- PSXStreamDecoder(Common::Rational frameRate);
- PSXStreamDecoder(CDSpeed speed, uint32 frameCount);
+ PSXStreamDecoder(CDSpeed speed, uint32 frameCount = 0);
virtual ~PSXStreamDecoder();
bool loadStream(Common::SeekableReadStream *stream);
@@ -75,22 +73,18 @@ public:
uint16 getHeight() const { return _surface->h; }
uint32 getFrameCount() const { return _frameCount; }
uint32 getElapsedTime() const;
+ uint32 getTimeToNextFrame() const;
const Graphics::Surface *decodeNextFrame();
Graphics::PixelFormat getPixelFormat() const { return _surface->format; }
bool endOfVideo() const { return _stream->pos() >= _stream->size(); }
-protected:
- // Hardcoded frame rate
- Common::Rational getFrameRate() const { return _frameRate; }
-
private:
void initCommon();
Common::SeekableReadStream *_stream;
Graphics::Surface *_surface;
- CDSpeed _speed;
uint32 _frameCount;
- Common::Rational _frameRate;
+ Audio::Timestamp _nextFrameStartTime;
Audio::SoundHandle _audHandle;
Audio::QueuingAudioStream *_audStream;
Commit: 8fea4968909eb5f3d154ae7f2964afba20033c50
https://github.com/scummvm/scummvm/commit/8fea4968909eb5f3d154ae7f2964afba20033c50
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2012-02-23T13:48:18-08:00
Commit Message:
VIDEO: Clarify which PSX streams we can play
Changed paths:
video/psx_decoder.h
diff --git a/video/psx_decoder.h b/video/psx_decoder.h
index 6218704..c8ad92c 100644
--- a/video/psx_decoder.h
+++ b/video/psx_decoder.h
@@ -48,6 +48,9 @@ namespace Video {
/**
* Decoder for PSX stream videos.
+ * This currently implements the most basic PSX stream format that is
+ * used by most games on the system. Special variants are not supported
+ * at this time.
*
* Video decoder used in engines:
* - sword1 (psx)
Commit: a352c3cc000fb13f0dae32e84a859a8fb5cb5966
https://github.com/scummvm/scummvm/commit/a352c3cc000fb13f0dae32e84a859a8fb5cb5966
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2012-02-23T13:48:18-08:00
Commit Message:
SWORD1: Add support for the PSX demo videos
Changed paths:
engines/sword1/animation.cpp
diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp
index a1ace0f..e25b986 100644
--- a/engines/sword1/animation.cpp
+++ b/engines/sword1/animation.cpp
@@ -88,8 +88,8 @@ static const char *const sequenceListPSX[20] = {
"candle1",
"geodrop1",
"vulture1",
- "",
- "" // no credits?
+ "", // not present
+ "" // credits are not a video
};
///////////////////////////////////////////////////////////////////////////////
@@ -173,7 +173,7 @@ bool MoviePlayer::load(uint32 id) {
filename = Common::String::format("%s.smk", sequenceList[id]);
break;
case kVideoDecoderPSX:
- filename = Common::String::format("%s.str", sequenceListPSX[id]);
+ filename = Common::String::format("%s.str", (_vm->_systemVars.isDemo) ? sequenceList[id] : sequenceListPSX[id]);
// Need to switch to true color
initGraphics(g_system->getWidth(), g_system->getHeight(), true, 0);
@@ -406,7 +406,8 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *
// For the PSX version, we'll try the PlayStation stream files
if (vm->isPsx()) {
- filename = Common::String(sequenceListPSX[id]) + ".str";
+ // The demo uses the normal file names
+ filename = ((vm->_systemVars.isDemo) ? Common::String(sequenceList[id]) : Common::String(sequenceListPSX[id])) + ".str";
if (Common::File::exists(filename)) {
#ifdef USE_RGB_COLOR
@@ -450,9 +451,11 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *
return NULL;
}
- Common::String buf = Common::String::format(_("Cutscene '%s' not found"), sequenceList[id]);
- GUI::MessageDialog dialog(buf, _("OK"));
- dialog.runModal();
+ if (!vm->isPsx() || scumm_stricmp(sequenceList[id], "enddemo") != 0) {
+ Common::String buf = Common::String::format(_("Cutscene '%s' not found"), sequenceList[id]);
+ GUI::MessageDialog dialog(buf, _("OK"));
+ dialog.runModal();
+ }
return NULL;
}
Commit: 7a3e0ea45300ba950d71ba0eae9381a0b0869f01
https://github.com/scummvm/scummvm/commit/7a3e0ea45300ba950d71ba0eae9381a0b0869f01
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2012-02-23T13:48:19-08:00
Commit Message:
SWORD1: Add some TODO's for PSX stream subtitles
And some other minor cleanup
Changed paths:
engines/sword1/animation.cpp
diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp
index e25b986..a3d732e 100644
--- a/engines/sword1/animation.cpp
+++ b/engines/sword1/animation.cpp
@@ -88,7 +88,7 @@ static const char *const sequenceListPSX[20] = {
"candle1",
"geodrop1",
"vulture1",
- "", // not present
+ "", // demo video not present
"" // credits are not a video
};
@@ -102,8 +102,8 @@ MoviePlayer::MoviePlayer(SwordEngine *vm, Text *textMan, ResMan *resMan, Audio::
_decoderType = decoderType;
_decoder = decoder;
- _white = (decoderType == kVideoDecoderPSX) ? _system->getScreenFormat().RGBToColor(0xff, 0xff, 0xff) : 255;
- _black = (decoderType == kVideoDecoderPSX) ? _system->getScreenFormat().RGBToColor(0x00, 0x00, 0x00) : 0;
+ _white = 255;
+ _black = 0;
}
MoviePlayer::~MoviePlayer() {
@@ -224,8 +224,9 @@ void MoviePlayer::play() {
}
void MoviePlayer::performPostProcessing(byte *screen) {
- // TODO
- if (_decoderType == kVideoDecoderPSX)
+ // TODO: We don't support the PSX stream videos yet
+ // nor using the PSX fonts to display subtitles.
+ if (_vm->isPsx())
return;
if (!_movieTexts.empty()) {
@@ -361,11 +362,11 @@ bool MoviePlayer::playVideo() {
}
uint32 MoviePlayer::getBlackColor() {
- return _black;
+ return (_decoderType == kVideoDecoderPSX) ? g_system->getScreenFormat().RGBToColor(0x00, 0x00, 0x00) : _black;
}
uint32 MoviePlayer::getWhiteColor() {
- return _white;
+ return (_decoderType == kVideoDecoderPSX) ? g_system->getScreenFormat().RGBToColor(0xFF, 0xFF, 0xFF) : _white;
}
void MoviePlayer::drawFramePSX(const Graphics::Surface *frame) {
Commit: 4637d55337d083d85bea762db7d59b47e92c0fbe
https://github.com/scummvm/scummvm/commit/4637d55337d083d85bea762db7d59b47e92c0fbe
Author: Willem Jan Palenstijn (wjp at usecode.org)
Date: 2012-02-23T13:49:59-08:00
Commit Message:
Merge pull request #171 from clone2727/psx-stream-2
This is a manual merge based on clone2727's merge of his branch
with the sword1 subtitle changes on master.
Changed paths:
A video/psx_decoder.cpp
A video/psx_decoder.h
engines/sword1/animation.cpp
engines/sword1/animation.h
engines/sword1/sword1.cpp
engines/sword2/animation.cpp
engines/sword2/animation.h
engines/sword2/function.cpp
engines/sword2/sword2.cpp
video/module.mk
diff --cc engines/sword1/animation.cpp
index e274e02,a3d732e..1e29640
--- a/engines/sword1/animation.cpp
+++ b/engines/sword1/animation.cpp
@@@ -215,10 -256,10 +265,10 @@@ void MoviePlayer::performPostProcessing
for (x = 0; x < _textWidth; x++) {
switch (src[x]) {
case BORDER_COL:
- dst[x] = findBlackPalIndex();
+ dst[x] = getBlackColor();
break;
case LETTER_COL:
- dst[x] = findTextColorPalIndex();
- dst[x] = getWhiteColor();
++ dst[x] = findTextColor();
break;
}
}
@@@ -367,52 -353,39 +422,90 @@@ bool MoviePlayer::playVideo()
_vm->_system->delayMillis(10);
}
- return !_vm->shouldQuit();
+ if (_decoderType == kVideoDecoderPSX) {
+ // Need to jump back to paletted color
+ initGraphics(g_system->getWidth(), g_system->getHeight(), true);
+ }
+
+ return !_vm->shouldQuit() && !skipped;
}
- byte MoviePlayer::findBlackPalIndex() {
- return _black;
+ uint32 MoviePlayer::getBlackColor() {
+ return (_decoderType == kVideoDecoderPSX) ? g_system->getScreenFormat().RGBToColor(0x00, 0x00, 0x00) : _black;
}
-
- byte MoviePlayer::findTextColorPalIndex() {
+
-uint32 MoviePlayer::getWhiteColor() {
- return (_decoderType == kVideoDecoderPSX) ? g_system->getScreenFormat().RGBToColor(0xFF, 0xFF, 0xFF) : _white;
++uint32 MoviePlayer::findTextColor() {
++ if (_decoderType == kVideoDecoderPSX) {
++ // We're in true color mode, so return the actual colors
++ switch (_textColor) {
++ case 1:
++ return g_system->getScreenFormat().RGBToColor(248, 252, 248);
++ case 2:
++ return g_system->getScreenFormat().RGBToColor(184, 188, 184);
++ case 3:
++ return g_system->getScreenFormat().RGBToColor(200, 120, 184);
++ case 4:
++ return g_system->getScreenFormat().RGBToColor(80, 152, 184);
++ }
++
++ return g_system->getScreenFormat().RGBToColor(0xFF, 0xFF, 0xFF);
++ }
++
+ switch (_textColor) {
+ case 1:
+ return _c1Color;
+ case 2:
+ return _c2Color;
+ case 3:
+ return _c3Color;
+ case 4:
+ return _c4Color;
+ }
+ return _c1Color;
+}
+
+void MoviePlayer::convertColor(byte r, byte g, byte b, float &h, float &s, float &v) {
+ float varR = r / 255.0f;
+ float varG = g / 255.0f;
+ float varB = b / 255.0f;
+
+ float min = MIN(varR, MIN(varG, varB));
+ float max = MAX(varR, MAX(varG, varB));
+
+ v = max;
+ float d = max - min;
+ s = max == 0.0f ? 0.0f : d / max;
+
+ if (min == max) {
+ h = 0.0f; // achromatic
+ } else {
+ if (max == varR)
+ h = (varG - varB) / d + (varG < varB ? 6.0f : 0.0f);
+ else if (max == varG)
+ h = (varB - varR) / d + 2.0f;
+ else
+ h = (varR - varG) / d + 4.0f;
+ h /= 6.0f;
+ }
}
+ void MoviePlayer::drawFramePSX(const Graphics::Surface *frame) {
+ // The PSX videos have half resolution
+
+ Graphics::Surface scaledFrame;
+ scaledFrame.create(frame->w, frame->h * 2, frame->format);
+
+ for (int y = 0; y < scaledFrame.h; y++)
+ memcpy(scaledFrame.getBasePtr(0, y), frame->getBasePtr(0, y / 2), scaledFrame.w * scaledFrame.format.bytesPerPixel);
+
+ uint16 x = (g_system->getWidth() - scaledFrame.w) / 2;
+ uint16 y = (g_system->getHeight() - scaledFrame.h) / 2;
+
+ _vm->_system->copyRectToScreen((byte *)scaledFrame.pixels, scaledFrame.pitch, x, y, scaledFrame.w, scaledFrame.h);
+
+ scaledFrame.free();
+ }
+
DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle)
: _mixer(mixer), _bgSoundHandle(bgSoundHandle) {
}
diff --cc engines/sword1/animation.h
index c436607,23dae7f..f64b03d
--- a/engines/sword1/animation.h
+++ b/engines/sword1/animation.h
@@@ -82,9 -80,7 +82,9 @@@ protected
OSystem *_system;
Common::List<MovieText> _movieTexts;
int _textX, _textY, _textWidth, _textHeight;
- uint32 _white, _black;
+ int _textColor;
- byte _black;
- byte _c1Color, _c2Color, _c3Color, _c4Color;
++ uint32 _black;
++ uint32 _c1Color, _c2Color, _c3Color, _c4Color;
DecoderType _decoderType;
Video::VideoDecoder *_decoder;
@@@ -93,10 -89,10 +93,11 @@@
bool playVideo();
void performPostProcessing(byte *screen);
+ void drawFramePSX(const Graphics::Surface *frame);
- byte findBlackPalIndex();
- byte findTextColorPalIndex();
+ uint32 getBlackColor();
- uint32 getWhiteColor();
++ uint32 findTextColor();
+ void convertColor(byte r, byte g, byte b, float &h, float &s, float &v);
};
MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *resMan, Audio::Mixer *snd, OSystem *system);
More information about the Scummvm-git-logs
mailing list