aboutsummaryrefslogtreecommitdiff
path: root/graphics/video/codecs
diff options
context:
space:
mode:
authorMatthew Hoops2010-05-23 18:33:55 +0000
committerMatthew Hoops2010-05-23 18:33:55 +0000
commit2f31b05651baf87ea07bc00cced798955a5fa6be (patch)
treeeedade6bd746422fe45e8c48c76d1dd667a45b20 /graphics/video/codecs
parente2a388e2f59f689cd89995013236e90a1b004264 (diff)
downloadscummvm-rg350-2f31b05651baf87ea07bc00cced798955a5fa6be.tar.gz
scummvm-rg350-2f31b05651baf87ea07bc00cced798955a5fa6be.tar.bz2
scummvm-rg350-2f31b05651baf87ea07bc00cced798955a5fa6be.zip
Move Mohawk's QuickTime code to graphics/ (and QDM2 to sound, disabled when Mohawk is not enabled) so SCI can use the code.
svn-id: r49165
Diffstat (limited to 'graphics/video/codecs')
-rw-r--r--graphics/video/codecs/cinepak.cpp287
-rw-r--r--graphics/video/codecs/cinepak.h81
-rw-r--r--graphics/video/codecs/mjpeg.cpp73
-rw-r--r--graphics/video/codecs/mjpeg.h58
-rw-r--r--graphics/video/codecs/qtrle.cpp420
-rw-r--r--graphics/video/codecs/qtrle.h58
-rw-r--r--graphics/video/codecs/rpza.cpp208
-rw-r--r--graphics/video/codecs/rpza.h49
-rw-r--r--graphics/video/codecs/smc.cpp385
-rw-r--r--graphics/video/codecs/smc.h59
10 files changed, 1678 insertions, 0 deletions
diff --git a/graphics/video/codecs/cinepak.cpp b/graphics/video/codecs/cinepak.cpp
new file mode 100644
index 0000000000..d3448bb8f7
--- /dev/null
+++ b/graphics/video/codecs/cinepak.cpp
@@ -0,0 +1,287 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "graphics/video/codecs/cinepak.h"
+
+#include "common/system.h"
+
+// Code here partially based off of ffmpeg ;)
+
+namespace Graphics {
+
+// Convert a color from YUV to RGB colorspace, Cinepak style.
+inline static void CPYUV2RGB(byte y, byte u, byte v, byte &r, byte &g, byte &b) {
+ r = CLIP<int>(y + 2 * (v - 128), 0, 255);
+ g = CLIP<int>(y - (u - 128) / 2 - (v - 128), 0, 255);
+ b = CLIP<int>(y + 2 * (u - 128), 0, 255);
+}
+
+#define PUT_PIXEL(offset, lum, u, v) \
+ CPYUV2RGB(lum, u, v, r, g, b); \
+ if (_pixelFormat.bytesPerPixel == 2) \
+ *((uint16 *)_curFrame.surface->pixels + offset) = _pixelFormat.RGBToColor(r, g, b); \
+ else \
+ *((uint32 *)_curFrame.surface->pixels + offset) = _pixelFormat.RGBToColor(r, g, b)
+
+CinepakDecoder::CinepakDecoder() : Codec() {
+ _curFrame.surface = NULL;
+ _curFrame.strips = NULL;
+ _y = 0;
+ _pixelFormat = g_system->getScreenFormat();
+}
+
+CinepakDecoder::~CinepakDecoder() {
+ if (_curFrame.surface)
+ _curFrame.surface->free();
+ delete[] _curFrame.strips;
+}
+
+Surface *CinepakDecoder::decodeImage(Common::SeekableReadStream *stream) {
+ _curFrame.flags = stream->readByte();
+ _curFrame.length = (stream->readByte() << 16) + stream->readUint16BE();
+ _curFrame.width = stream->readUint16BE();
+ _curFrame.height = stream->readUint16BE();
+ _curFrame.stripCount = stream->readUint16BE();
+
+ if (_curFrame.strips == NULL)
+ _curFrame.strips = new CinepakStrip[_curFrame.stripCount];
+
+ debug (4, "Cinepak Frame: Width = %d, Height = %d, Strip Count = %d", _curFrame.width, _curFrame.height, _curFrame.stripCount);
+
+#if 0
+ // Borrowed from FFMPEG. This should cut out the extra data Cinepak for Sega has (which is useless).
+ // The theory behind this is that this is here to confuse standard Cinepak decoders. But, we won't let that happen! ;)
+ if (_curFrame.length != (uint32)stream->size()) {
+ if (stream->readUint16BE() == 0xFE00)
+ stream->readUint32BE();
+ }
+#endif
+
+ if (!_curFrame.surface) {
+ _curFrame.surface = new Surface();
+ _curFrame.surface->create(_curFrame.width, _curFrame.height, _pixelFormat.bytesPerPixel);
+ }
+
+ // Reset the y variable.
+ _y = 0;
+
+ for (uint16 i = 0; i < _curFrame.stripCount; i++) {
+ if (i > 0 && !(_curFrame.flags & 1)) { // Use codebooks from last strip
+ for (uint16 j = 0; j < 256; j++) {
+ _curFrame.strips[i].v1_codebook[j] = _curFrame.strips[i - 1].v1_codebook[j];
+ _curFrame.strips[i].v4_codebook[j] = _curFrame.strips[i - 1].v4_codebook[j];
+ }
+ }
+
+ _curFrame.strips[i].id = stream->readUint16BE();
+ _curFrame.strips[i].length = stream->readUint16BE() - 12; // Subtract the 12 byte header
+ _curFrame.strips[i].rect.top = _y; stream->readUint16BE(); // Ignore, substitute with our own.
+ _curFrame.strips[i].rect.left = 0; stream->readUint16BE(); // Ignore, substitute with our own
+ _curFrame.strips[i].rect.bottom = _y + stream->readUint16BE();
+ _curFrame.strips[i].rect.right = _curFrame.width; stream->readUint16BE(); // Ignore, substitute with our own
+
+ //printf ("Left = %d, Top = %d, Right = %d, Bottom = %d\n", _curFrame.strips[i].rect.left, _curFrame.strips[i].rect.top, _curFrame.strips[i].rect.right, _curFrame.strips[i].rect.bottom);
+
+ // Sanity check. Because Cinepak is based on 4x4 blocks, the width and height of each strip needs to be divisible by 4.
+ assert(!(_curFrame.strips[i].rect.width() % 4) && !(_curFrame.strips[i].rect.height() % 4));
+
+ uint32 pos = stream->pos();
+
+ while ((uint32)stream->pos() < (pos + _curFrame.strips[i].length) && !stream->eos()) {
+ byte chunkID = stream->readByte();
+
+ if (stream->eos())
+ break;
+
+ // Chunk Size is 24-bit, ignore the first 4 bytes
+ uint32 chunkSize = stream->readByte() << 16;
+ chunkSize += stream->readUint16BE() - 4;
+
+ int32 startPos = stream->pos();
+
+ switch (chunkID) {
+ case 0x20:
+ case 0x21:
+ case 0x24:
+ case 0x25:
+ loadCodebook(stream, i, 4, chunkID, chunkSize);
+ break;
+ case 0x22:
+ case 0x23:
+ case 0x26:
+ case 0x27:
+ loadCodebook(stream, i, 1, chunkID, chunkSize);
+ break;
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ decodeVectors(stream, i, chunkID, chunkSize);
+ break;
+ default:
+ warning("Unknown Cinepak chunk ID %02x", chunkID);
+ return _curFrame.surface;
+ }
+
+ if (stream->pos() != startPos + (int32)chunkSize)
+ stream->seek(startPos + chunkSize);
+ }
+
+ _y = _curFrame.strips[i].rect.bottom;
+ }
+
+ return _curFrame.surface;
+}
+
+void CinepakDecoder::loadCodebook(Common::SeekableReadStream *stream, uint16 strip, byte codebookType, byte chunkID, uint32 chunkSize) {
+ CinepakCodebook *codebook = (codebookType == 1) ? _curFrame.strips[strip].v1_codebook : _curFrame.strips[strip].v4_codebook;
+
+ int32 startPos = stream->pos();
+ uint32 flag = 0, mask = 0;
+
+ for (uint16 i = 0; i < 256; i++) {
+ if ((chunkID & 0x01) && !(mask >>= 1)) {
+ if ((stream->pos() - startPos + 4) > (int32)chunkSize)
+ break;
+
+ flag = stream->readUint32BE();
+ mask = 0x80000000;
+ }
+
+ if (!(chunkID & 0x01) || (flag & mask)) {
+ byte n = (chunkID & 0x04) ? 4 : 6;
+ if ((stream->pos() - startPos + n) > (int32)chunkSize)
+ break;
+
+ for (byte j = 0; j < 4; j++)
+ codebook[i].y[j] = stream->readByte();
+
+ if (n == 6) {
+ codebook[i].u = stream->readByte() + 128;
+ codebook[i].v = stream->readByte() + 128;
+ } else {
+ /* this codebook type indicates either greyscale or
+ * palettized video; if palettized, U & V components will
+ * not be used so it is safe to set them to 128 for the
+ * benefit of greyscale rendering in YUV420P */
+ codebook[i].u = 128;
+ codebook[i].v = 128;
+ }
+ }
+ }
+}
+
+void CinepakDecoder::decodeVectors(Common::SeekableReadStream *stream, uint16 strip, byte chunkID, uint32 chunkSize) {
+ uint32 flag = 0, mask = 0;
+ uint32 iy[4];
+ int32 startPos = stream->pos();
+ byte r = 0, g = 0, b = 0;
+
+ for (uint16 y = _curFrame.strips[strip].rect.top; y < _curFrame.strips[strip].rect.bottom; y += 4) {
+ iy[0] = _curFrame.strips[strip].rect.left + y * _curFrame.width;
+ iy[1] = iy[0] + _curFrame.width;
+ iy[2] = iy[1] + _curFrame.width;
+ iy[3] = iy[2] + _curFrame.width;
+
+ for (uint16 x = _curFrame.strips[strip].rect.left; x < _curFrame.strips[strip].rect.right; x += 4) {
+ if ((chunkID & 0x01) && !(mask >>= 1)) {
+ if ((stream->pos() - startPos + 4) > (int32)chunkSize)
+ return;
+
+ flag = stream->readUint32BE();
+ mask = 0x80000000;
+ }
+
+ if (!(chunkID & 0x01) || (flag & mask)) {
+ if (!(chunkID & 0x02) && !(mask >>= 1)) {
+ if ((stream->pos() - startPos + 4) > (int32)chunkSize)
+ return;
+
+ flag = stream->readUint32BE();
+ mask = 0x80000000;
+ }
+
+ if ((chunkID & 0x02) || (~flag & mask)) {
+ if ((stream->pos() - startPos + 1) > (int32)chunkSize)
+ return;
+
+ // Get the codebook
+ CinepakCodebook codebook = _curFrame.strips[strip].v1_codebook[stream->readByte()];
+
+ PUT_PIXEL(iy[0] + 0, codebook.y[0], codebook.u, codebook.v);
+ PUT_PIXEL(iy[0] + 1, codebook.y[0], codebook.u, codebook.v);
+ PUT_PIXEL(iy[1] + 0, codebook.y[0], codebook.u, codebook.v);
+ PUT_PIXEL(iy[1] + 1, codebook.y[0], codebook.u, codebook.v);
+
+ PUT_PIXEL(iy[0] + 2, codebook.y[1], codebook.u, codebook.v);
+ PUT_PIXEL(iy[0] + 3, codebook.y[1], codebook.u, codebook.v);
+ PUT_PIXEL(iy[1] + 2, codebook.y[1], codebook.u, codebook.v);
+ PUT_PIXEL(iy[1] + 3, codebook.y[1], codebook.u, codebook.v);
+
+ PUT_PIXEL(iy[2] + 0, codebook.y[2], codebook.u, codebook.v);
+ PUT_PIXEL(iy[2] + 1, codebook.y[2], codebook.u, codebook.v);
+ PUT_PIXEL(iy[3] + 0, codebook.y[2], codebook.u, codebook.v);
+ PUT_PIXEL(iy[3] + 1, codebook.y[2], codebook.u, codebook.v);
+
+ PUT_PIXEL(iy[2] + 2, codebook.y[3], codebook.u, codebook.v);
+ PUT_PIXEL(iy[2] + 3, codebook.y[3], codebook.u, codebook.v);
+ PUT_PIXEL(iy[3] + 2, codebook.y[3], codebook.u, codebook.v);
+ PUT_PIXEL(iy[3] + 3, codebook.y[3], codebook.u, codebook.v);
+ } else if (flag & mask) {
+ if ((stream->pos() - startPos + 4) > (int32)chunkSize)
+ return;
+
+ CinepakCodebook codebook = _curFrame.strips[strip].v4_codebook[stream->readByte()];
+ PUT_PIXEL(iy[0] + 0, codebook.y[0], codebook.u, codebook.v);
+ PUT_PIXEL(iy[0] + 1, codebook.y[1], codebook.u, codebook.v);
+ PUT_PIXEL(iy[1] + 0, codebook.y[2], codebook.u, codebook.v);
+ PUT_PIXEL(iy[1] + 1, codebook.y[3], codebook.u, codebook.v);
+
+ codebook = _curFrame.strips[strip].v4_codebook[stream->readByte()];
+ PUT_PIXEL(iy[0] + 2, codebook.y[0], codebook.u, codebook.v);
+ PUT_PIXEL(iy[0] + 3, codebook.y[1], codebook.u, codebook.v);
+ PUT_PIXEL(iy[1] + 2, codebook.y[2], codebook.u, codebook.v);
+ PUT_PIXEL(iy[1] + 3, codebook.y[3], codebook.u, codebook.v);
+
+ codebook = _curFrame.strips[strip].v4_codebook[stream->readByte()];
+ PUT_PIXEL(iy[2] + 0, codebook.y[0], codebook.u, codebook.v);
+ PUT_PIXEL(iy[2] + 1, codebook.y[1], codebook.u, codebook.v);
+ PUT_PIXEL(iy[3] + 0, codebook.y[2], codebook.u, codebook.v);
+ PUT_PIXEL(iy[3] + 1, codebook.y[3], codebook.u, codebook.v);
+
+ codebook = _curFrame.strips[strip].v4_codebook[stream->readByte()];
+ PUT_PIXEL(iy[2] + 2, codebook.y[0], codebook.u, codebook.v);
+ PUT_PIXEL(iy[2] + 3, codebook.y[1], codebook.u, codebook.v);
+ PUT_PIXEL(iy[3] + 2, codebook.y[2], codebook.u, codebook.v);
+ PUT_PIXEL(iy[3] + 3, codebook.y[3], codebook.u, codebook.v);
+ }
+ }
+
+ for (byte i = 0; i < 4; i++)
+ iy[i] += 4;
+ }
+ }
+}
+
+} // End of namespace Graphics
diff --git a/graphics/video/codecs/cinepak.h b/graphics/video/codecs/cinepak.h
new file mode 100644
index 0000000000..92351cdba8
--- /dev/null
+++ b/graphics/video/codecs/cinepak.h
@@ -0,0 +1,81 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef GRAPHICS_CINEPAK_H
+#define GRAPHICS_CINEPAK_H
+
+#include "common/scummsys.h"
+#include "common/stream.h"
+#include "common/rect.h"
+#include "graphics/surface.h"
+#include "graphics/pixelformat.h"
+
+#include "graphics/video/codecs/codec.h"
+
+namespace Graphics {
+
+struct CinepakCodebook {
+ byte y[4];
+ byte u, v;
+};
+
+struct CinepakStrip {
+ uint16 id;
+ uint16 length;
+ Common::Rect rect;
+ CinepakCodebook v1_codebook[256], v4_codebook[256];
+};
+
+struct CinepakFrame {
+ byte flags;
+ uint32 length;
+ uint16 width;
+ uint16 height;
+ uint16 stripCount;
+ CinepakStrip *strips;
+
+ Surface *surface;
+};
+
+class CinepakDecoder : public Codec {
+public:
+ CinepakDecoder();
+ ~CinepakDecoder();
+
+ Surface *decodeImage(Common::SeekableReadStream *stream);
+ PixelFormat getPixelFormat() const { return _pixelFormat; }
+
+private:
+ CinepakFrame _curFrame;
+ int32 _y;
+ PixelFormat _pixelFormat;
+
+ void loadCodebook(Common::SeekableReadStream *stream, uint16 strip, byte codebookType, byte chunkID, uint32 chunkSize);
+ void decodeVectors(Common::SeekableReadStream *stream, uint16 strip, byte chunkID, uint32 chunkSize);
+};
+
+} // End of namespace Graphics
+
+#endif
diff --git a/graphics/video/codecs/mjpeg.cpp b/graphics/video/codecs/mjpeg.cpp
new file mode 100644
index 0000000000..76363036ee
--- /dev/null
+++ b/graphics/video/codecs/mjpeg.cpp
@@ -0,0 +1,73 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/system.h"
+#include "graphics/conversion.h" // For YUV2RGB
+
+#include "graphics/video/codecs/mjpeg.h"
+
+namespace Graphics {
+
+JPEGDecoder::JPEGDecoder() : Codec() {
+ _jpeg = new JPEG();
+ _pixelFormat = g_system->getScreenFormat();
+ _surface = NULL;
+}
+
+JPEGDecoder::~JPEGDecoder() {
+ delete _jpeg;
+
+ if (_surface) {
+ _surface->free();
+ delete _surface;
+ }
+}
+
+Surface *JPEGDecoder::decodeImage(Common::SeekableReadStream* stream) {
+ _jpeg->read(stream);
+ Surface *ySurface = _jpeg->getComponent(1);
+ Surface *uSurface = _jpeg->getComponent(2);
+ Surface *vSurface = _jpeg->getComponent(3);
+
+ if (!_surface) {
+ _surface = new Surface();
+ _surface->create(ySurface->w, ySurface->h, _pixelFormat.bytesPerPixel);
+ }
+
+ for (uint16 i = 0; i < _surface->h; i++) {
+ for (uint16 j = 0; j < _surface->w; j++) {
+ byte r = 0, g = 0, b = 0;
+ YUV2RGB(*((byte *)ySurface->getBasePtr(j, i)), *((byte *)uSurface->getBasePtr(j, i)), *((byte *)vSurface->getBasePtr(j, i)), r, g, b);
+ if (_pixelFormat.bytesPerPixel == 2)
+ *((uint16 *)_surface->getBasePtr(j, i)) = _pixelFormat.RGBToColor(r, g, b);
+ else
+ *((uint32 *)_surface->getBasePtr(j, i)) = _pixelFormat.RGBToColor(r, g, b);
+ }
+ }
+
+ return _surface;
+}
+
+} // End of namespace Graphics
diff --git a/graphics/video/codecs/mjpeg.h b/graphics/video/codecs/mjpeg.h
new file mode 100644
index 0000000000..ab364fb5be
--- /dev/null
+++ b/graphics/video/codecs/mjpeg.h
@@ -0,0 +1,58 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef GRAPHICS_MJPEG_H
+#define GRAPHICS_MJPEG_H
+
+#include "common/scummsys.h"
+#include "common/stream.h"
+
+#include "graphics/video/codecs/codec.h"
+#include "graphics/jpeg.h"
+#include "graphics/pixelformat.h"
+
+namespace Graphics {
+
+// Motion JPEG Decoder
+// Basically a wrapper around JPEG which converts to RGB and also functions
+// as a Codec.
+
+class JPEGDecoder : public Codec {
+public:
+ JPEGDecoder();
+ ~JPEGDecoder();
+
+ Surface *decodeImage(Common::SeekableReadStream *stream);
+ PixelFormat getPixelFormat() const { return _pixelFormat; }
+
+private:
+ PixelFormat _pixelFormat;
+ JPEG *_jpeg;
+ Surface *_surface;
+};
+
+} // End of namespace Graphics
+
+#endif
diff --git a/graphics/video/codecs/qtrle.cpp b/graphics/video/codecs/qtrle.cpp
new file mode 100644
index 0000000000..3e3fd4cfce
--- /dev/null
+++ b/graphics/video/codecs/qtrle.cpp
@@ -0,0 +1,420 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+// QuickTime RLE Decoder
+// Based off ffmpeg's QuickTime RLE decoder (written by Mike Melanson)
+
+#include "graphics/video/codecs/qtrle.h"
+
+#include "common/scummsys.h"
+#include "common/stream.h"
+#include "common/system.h"
+#include "graphics/colormasks.h"
+#include "graphics/surface.h"
+
+namespace Graphics {
+
+QTRLEDecoder::QTRLEDecoder(uint16 width, uint16 height, byte bitsPerPixel) : Codec() {
+ _bitsPerPixel = bitsPerPixel;
+ _pixelFormat = g_system->getScreenFormat();
+
+ // We need to increase the surface size to a multiple of 4
+ uint16 wMod = width % 4;
+ if(wMod != 0)
+ width += 4 - wMod;
+
+ debug(2, "QTRLE corrected width: %d", width);
+
+ _surface = new Surface();
+ _surface->create(width, height, _bitsPerPixel <= 8 ? 1 : _pixelFormat.bytesPerPixel);
+}
+
+#define CHECK_STREAM_PTR(n) \
+ if ((stream->pos() + n) > stream->size()) { \
+ warning ("Problem: stream out of bounds (%d >= %d)", stream->pos() + n, stream->size()); \
+ return; \
+ }
+
+#define CHECK_PIXEL_PTR(n) \
+ if ((int32)pixelPtr + n > _surface->w * _surface->h) { \
+ warning ("Problem: pixel ptr = %d, pixel limit = %d", pixelPtr + n, _surface->w * _surface->h); \
+ return; \
+ } \
+
+void QTRLEDecoder::decode1(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange) {
+ uint32 pixelPtr = 0;
+ byte *rgb = (byte *)_surface->pixels;
+
+ while (linesToChange) {
+ CHECK_STREAM_PTR(2);
+ byte skip = stream->readByte();
+ int8 rleCode = stream->readSByte();
+
+ if (rleCode == 0)
+ break;
+
+ if (skip & 0x80) {
+ linesToChange--;
+ rowPtr += _surface->w;
+ pixelPtr = rowPtr + 2 * (skip & 0x7f);
+ } else
+ pixelPtr += 2 * skip;
+
+ if (rleCode < 0) {
+ // decode the run length code
+ rleCode = -rleCode;
+ // get the next 2 bytes from the stream, treat them as groups of 8 pixels, and output them rleCode times */
+ CHECK_STREAM_PTR(2);
+ byte pi0 = stream->readByte();
+ byte pi1 = stream->readByte();
+ CHECK_PIXEL_PTR(rleCode * 2);
+
+ while (rleCode--) {
+ rgb[pixelPtr++] = pi0;
+ rgb[pixelPtr++] = pi1;
+ }
+ } else {
+ // copy the same pixel directly to output 2 times
+ rleCode *= 2;
+ CHECK_STREAM_PTR(rleCode);
+ CHECK_PIXEL_PTR(rleCode);
+
+ while (rleCode--)
+ rgb[pixelPtr++] = stream->readByte();
+ }
+ }
+}
+
+void QTRLEDecoder::decode2_4(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange, byte bpp) {
+ uint32 pixelPtr = 0;
+ byte *rgb = (byte *)_surface->pixels;
+ byte numPixels = (bpp == 4) ? 8 : 16;
+
+ while (linesToChange--) {
+ CHECK_STREAM_PTR(2);
+ pixelPtr = rowPtr + (numPixels * (stream->readByte() - 1));
+
+ for (int8 rleCode = stream->readSByte(); rleCode != -1; rleCode = stream->readSByte()) {
+ if (rleCode == 0) {
+ // there's another skip code in the stream
+ CHECK_STREAM_PTR(1);
+ pixelPtr += (numPixels * (stream->readByte() - 1));
+ } else if (rleCode < 0) {
+ // decode the run length code
+ rleCode = -rleCode;
+
+ // get the next 4 bytes from the stream, treat them as palette indices, and output them rleCode times */
+ CHECK_STREAM_PTR(4);
+
+ byte pi[16]; // 16 palette indices
+
+ for (int8 i = numPixels - 1; i >= 0; i--) {
+ pi[numPixels - 1 - i] = (stream->readByte() >> ((i * bpp) & 0x07)) & ((1 << bpp) - 1);
+
+ // FIXME: Is this right?
+ //stream_ptr += ((i & ((num_pixels>>2)-1)) == 0);
+ if ((i & ((numPixels >> 2) - 1)) == 0)
+ stream->readByte();
+ }
+
+ CHECK_PIXEL_PTR(rleCode * numPixels);
+
+ while (rleCode--)
+ for (byte i = 0; i < numPixels; i++)
+ rgb[pixelPtr++] = pi[i];
+ } else {
+ // copy the same pixel directly to output 4 times
+ rleCode *= 4;
+ CHECK_STREAM_PTR(rleCode);
+ CHECK_PIXEL_PTR(rleCode * (numPixels >> 2));
+
+ while (rleCode--) {
+ byte temp = stream->readByte();
+ if (bpp == 4) {
+ rgb[pixelPtr++] = (temp >> 4) & 0x0f;
+ rgb[pixelPtr++] = temp & 0x0f;
+ } else {
+ rgb[pixelPtr++] = (temp >> 6) & 0x03;
+ rgb[pixelPtr++] = (temp >> 4) & 0x03;
+ rgb[pixelPtr++] = (temp >> 2) & 0x03;
+ rgb[pixelPtr++] = temp & 0x03;
+ }
+ }
+ }
+ }
+
+ rowPtr += _surface->w;
+ }
+}
+
+void QTRLEDecoder::decode8(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange) {
+ uint32 pixelPtr = 0;
+ byte *rgb = (byte *)_surface->pixels;
+
+ while (linesToChange--) {
+ CHECK_STREAM_PTR(2);
+ pixelPtr = rowPtr + 4 * (stream->readByte() - 1);
+
+ for (int8 rleCode = stream->readSByte(); rleCode != -1; rleCode = stream->readSByte()) {
+ if (rleCode == 0) {
+ // there's another skip code in the stream
+ CHECK_STREAM_PTR(1);
+ pixelPtr += 4 * (stream->readByte() - 1);
+ } else if (rleCode < 0) {
+ // decode the run length code
+ rleCode = -rleCode;
+
+ // get the next 4 bytes from the stream, treat them as palette indices, and output them rleCode times
+ CHECK_STREAM_PTR(4);
+
+ byte pi[4]; // 4 palette indexes
+
+ for (byte i = 0; i < 4; i++)
+ pi[i] = stream->readByte();
+
+ CHECK_PIXEL_PTR(rleCode * 4);
+
+ while (rleCode--)
+ for (byte i = 0; i < 4; i++)
+ rgb[pixelPtr++] = pi[i];
+ } else {
+ // copy the same pixel directly to output 4 times
+ rleCode *= 4;
+ CHECK_STREAM_PTR(rleCode);
+ CHECK_PIXEL_PTR(rleCode);
+
+ while (rleCode--)
+ rgb[pixelPtr++] = stream->readByte();
+ }
+ }
+
+ rowPtr += _surface->w;
+ }
+}
+
+void QTRLEDecoder::decode16(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange) {
+ uint32 pixelPtr = 0;
+ OverlayColor *rgb = (OverlayColor *)_surface->pixels;
+
+ while (linesToChange--) {
+ CHECK_STREAM_PTR(2);
+ pixelPtr = rowPtr + stream->readByte() - 1;
+
+ for (int8 rleCode = stream->readSByte(); rleCode != -1; rleCode = stream->readSByte()) {
+ if (rleCode == 0) {
+ // there's another skip code in the stream
+ CHECK_STREAM_PTR(1);
+ pixelPtr += stream->readByte() - 1;
+ } else if (rleCode < 0) {
+ // decode the run length code
+ rleCode = -rleCode;
+ CHECK_STREAM_PTR(2);
+
+ uint16 rgb16 = stream->readUint16BE();
+
+ CHECK_PIXEL_PTR(rleCode);
+
+ while (rleCode--) {
+ // Convert from RGB555 to the format specified by the Overlay
+ byte r = 0, g = 0, b = 0;
+ colorToRGB<ColorMasks<555> >(rgb16, r, g, b);
+ rgb[pixelPtr++] = _pixelFormat.RGBToColor(r, g, b);
+ }
+ } else {
+ CHECK_STREAM_PTR(rleCode * 2);
+ CHECK_PIXEL_PTR(rleCode);
+
+ // copy pixels directly to output
+ while (rleCode--) {
+ uint16 rgb16 = stream->readUint16BE();
+
+ // Convert from RGB555 to the format specified by the Overlay
+ byte r = 0, g = 0, b = 0;
+ colorToRGB<ColorMasks<555> >(rgb16, r, g, b);
+ rgb[pixelPtr++] = _pixelFormat.RGBToColor(r, g, b);
+ }
+ }
+ }
+
+ rowPtr += _surface->w;
+ }
+}
+
+void QTRLEDecoder::decode24(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange) {
+ uint32 pixelPtr = 0;
+ OverlayColor *rgb = (OverlayColor *)_surface->pixels;
+
+ while (linesToChange--) {
+ CHECK_STREAM_PTR(2);
+ pixelPtr = rowPtr + stream->readByte() - 1;
+
+ for (int8 rleCode = stream->readSByte(); rleCode != -1; rleCode = stream->readSByte()) {
+ if (rleCode == 0) {
+ // there's another skip code in the stream
+ CHECK_STREAM_PTR(1);
+ pixelPtr += stream->readByte() - 1;
+ } else if (rleCode < 0) {
+ // decode the run length code
+ rleCode = -rleCode;
+
+ CHECK_STREAM_PTR(3);
+
+ byte r = stream->readByte();
+ byte g = stream->readByte();
+ byte b = stream->readByte();
+
+ CHECK_PIXEL_PTR(rleCode);
+
+ while (rleCode--)
+ rgb[pixelPtr++] = _pixelFormat.RGBToColor(r, g, b);
+ } else {
+ CHECK_STREAM_PTR(rleCode * 3);
+ CHECK_PIXEL_PTR(rleCode);
+
+ // copy pixels directly to output
+ while (rleCode--) {
+ byte r = stream->readByte();
+ byte g = stream->readByte();
+ byte b = stream->readByte();
+ rgb[pixelPtr++] = _pixelFormat.RGBToColor(r, g, b);
+ }
+ }
+ }
+
+ rowPtr += _surface->w;
+ }
+}
+
+void QTRLEDecoder::decode32(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange) {
+ uint32 pixelPtr = 0;
+ OverlayColor *rgb = (OverlayColor *)_surface->pixels;
+
+ while (linesToChange--) {
+ CHECK_STREAM_PTR(2);
+ pixelPtr = rowPtr + stream->readByte() - 1;
+
+ for (int8 rleCode = stream->readSByte(); rleCode != -1; rleCode = stream->readSByte()) {
+ if (rleCode == 0) {
+ // there's another skip code in the stream
+ CHECK_STREAM_PTR(1);
+ pixelPtr += stream->readByte() - 1;
+ } else if (rleCode < 0) {
+ // decode the run length code
+ rleCode = -rleCode;
+
+ CHECK_STREAM_PTR(4);
+
+ byte a = stream->readByte();
+ byte r = stream->readByte();
+ byte g = stream->readByte();
+ byte b = stream->readByte();
+
+ CHECK_PIXEL_PTR(rleCode);
+
+ while (rleCode--)
+ rgb[pixelPtr++] = _pixelFormat.ARGBToColor(a, r, g, b);
+ } else {
+ CHECK_STREAM_PTR(rleCode * 4);
+ CHECK_PIXEL_PTR(rleCode);
+
+ // copy pixels directly to output
+ while (rleCode--) {
+ byte a = stream->readByte();
+ byte r = stream->readByte();
+ byte g = stream->readByte();
+ byte b = stream->readByte();
+ rgb[pixelPtr++] = _pixelFormat.ARGBToColor(a, r, g, b);
+ }
+ }
+ }
+
+ rowPtr += _surface->w;
+ }
+}
+
+Surface *QTRLEDecoder::decodeImage(Common::SeekableReadStream *stream) {
+ uint16 start_line = 0;
+ uint16 height = _surface->h;
+
+ // check if this frame is even supposed to change
+ if (stream->size() < 8)
+ return _surface;
+
+ // start after the chunk size
+ stream->readUint32BE();
+
+ // fetch the header
+ uint16 header = stream->readUint16BE();
+
+ // if a header is present, fetch additional decoding parameters
+ if (header & 8) {
+ if(stream->size() < 14)
+ return _surface;
+ start_line = stream->readUint16BE();
+ stream->readUint16BE(); // Unknown
+ height = stream->readUint16BE();
+ stream->readUint16BE(); // Unknown
+ }
+
+ uint32 row_ptr = _surface->w * start_line;
+
+ switch (_bitsPerPixel) {
+ case 1:
+ case 33:
+ decode1(stream, row_ptr, height);
+ break;
+ case 2:
+ case 34:
+ decode2_4(stream, row_ptr, height, 2);
+ break;
+ case 4:
+ case 36:
+ decode2_4(stream, row_ptr, height, 4);
+ break;
+ case 8:
+ case 40:
+ decode8(stream, row_ptr, height);
+ break;
+ case 16:
+ decode16(stream, row_ptr, height);
+ break;
+ case 24:
+ decode24(stream, row_ptr, height);
+ break;
+ case 32:
+ decode32(stream, row_ptr, height);
+ break;
+ default:
+ error ("Unsupported bits per pixel %d", _bitsPerPixel);
+ }
+
+ return _surface;
+}
+
+QTRLEDecoder::~QTRLEDecoder() {
+ _surface->free();
+}
+
+} // End of namespace Graphics
diff --git a/graphics/video/codecs/qtrle.h b/graphics/video/codecs/qtrle.h
new file mode 100644
index 0000000000..efbef14411
--- /dev/null
+++ b/graphics/video/codecs/qtrle.h
@@ -0,0 +1,58 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef GRAPHICS_VIDEO_QTRLE_H
+#define GRAPHICS_VIDEO_QTRLE_H
+
+#include "graphics/pixelformat.h"
+#include "graphics/video/codecs/codec.h"
+
+namespace Graphics {
+
+class QTRLEDecoder : public Codec {
+public:
+ QTRLEDecoder(uint16 width, uint16 height, byte bitsPerPixel);
+ ~QTRLEDecoder();
+
+ Surface *decodeImage(Common::SeekableReadStream *stream);
+ PixelFormat getPixelFormat() const { return _pixelFormat; }
+
+private:
+ byte _bitsPerPixel;
+
+ Surface *_surface;
+ PixelFormat _pixelFormat;
+
+ void decode1(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange);
+ void decode2_4(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange, byte bpp);
+ void decode8(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange);
+ void decode16(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange);
+ void decode24(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange);
+ void decode32(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange);
+};
+
+} // End of namespace Graphics
+
+#endif
diff --git a/graphics/video/codecs/rpza.cpp b/graphics/video/codecs/rpza.cpp
new file mode 100644
index 0000000000..f0ed72e730
--- /dev/null
+++ b/graphics/video/codecs/rpza.cpp
@@ -0,0 +1,208 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+ // Based off ffmpeg's RPZA decoder
+
+#include "graphics/video/codecs/rpza.h"
+
+#include "common/system.h"
+#include "graphics/colormasks.h"
+
+namespace Graphics {
+
+RPZADecoder::RPZADecoder(uint16 width, uint16 height) : Codec() {
+ _pixelFormat = g_system->getScreenFormat();
+
+ // We need to increase the surface size to a multiple of 4
+ uint16 wMod = width % 4;
+ if(wMod != 0)
+ width += 4 - wMod;
+
+ debug(2, "RPZA corrected width: %d", width);
+
+ _surface = new Surface();
+ _surface->create(width, height, _pixelFormat.bytesPerPixel);
+}
+
+#define ADVANCE_BLOCK() \
+ pixelPtr += 4; \
+ if (pixelPtr >= _surface->w) { \
+ pixelPtr = 0; \
+ rowPtr += _surface->w * 4; \
+ } \
+ totalBlocks--; \
+ if (totalBlocks < 0) \
+ error("block counter just went negative (this should not happen)") \
+
+// Convert from RGB555 to the format specified by the screen
+#define PUT_PIXEL(color) \
+ if ((int32)blockPtr < _surface->w * _surface->h) { \
+ byte r = 0, g = 0, b = 0; \
+ colorToRGB<ColorMasks<555> >(color, r, g, b); \
+ if (_pixelFormat.bytesPerPixel == 2) \
+ *((uint16 *)_surface->pixels + blockPtr) = _pixelFormat.RGBToColor(r, g, b); \
+ else \
+ *((uint32 *)_surface->pixels + blockPtr) = _pixelFormat.RGBToColor(r, g, b); \
+ } \
+ blockPtr++
+
+Surface *RPZADecoder::decodeImage(Common::SeekableReadStream *stream) {
+ uint16 colorA = 0, colorB = 0;
+ uint16 color4[4];
+
+ uint32 rowPtr = 0;
+ uint32 pixelPtr = 0;
+ uint32 blockPtr = 0;
+ uint32 rowInc = _surface->w - 4;
+ uint16 ta;
+ uint16 tb;
+
+ // First byte is always 0xe1. Warn if it's different
+ byte firstByte = stream->readByte();
+ if (firstByte != 0xe1)
+ warning("First RPZA chunk byte is 0x%02x instead of 0xe1", firstByte);
+
+ // Get chunk size, ingnoring first byte
+ uint32 chunkSize = stream->readUint16BE() << 8;
+ chunkSize += stream->readByte();
+
+ // If length mismatch use size from MOV file and try to decode anyway
+ if (chunkSize != (uint32)stream->size()) {
+ warning("MOV chunk size != encoded chunk size; using MOV chunk size");
+ chunkSize = stream->size();
+ }
+
+ // Number of 4x4 blocks in frame
+ int32 totalBlocks = ((_surface->w + 3) / 4) * ((_surface->h + 3) / 4);
+
+ // Process chunk data
+ while ((uint32)stream->pos() < chunkSize) {
+ byte opcode = stream->readByte(); // Get opcode
+ byte numBlocks = (opcode & 0x1f) + 1; // Extract block counter from opcode
+
+ // If opcode MSbit is 0, we need more data to decide what to do
+ if ((opcode & 0x80) == 0) {
+ colorA = (opcode << 8) | stream->readByte();
+ opcode = 0;
+ if (stream->readByte() & 0x80) {
+ // Must behave as opcode 110xxxxx, using colorA computed
+ // above. Use fake opcode 0x20 to enter switch block at
+ // the right place
+ opcode = 0x20;
+ numBlocks = 1;
+ }
+ stream->seek(-1, SEEK_CUR);
+ }
+
+ switch (opcode & 0xe0) {
+ case 0x80: // Skip blocks
+ while (numBlocks--) {
+ ADVANCE_BLOCK();
+ }
+ break;
+ case 0xa0: // Fill blocks with one color
+ colorA = stream->readUint16BE();
+ while (numBlocks--) {
+ blockPtr = rowPtr + pixelPtr;
+ for (byte pixel_y = 0; pixel_y < 4; pixel_y++) {
+ for (byte pixel_x = 0; pixel_x < 4; pixel_x++) {
+ PUT_PIXEL(colorA);
+ }
+ blockPtr += rowInc;
+ }
+ ADVANCE_BLOCK();
+ }
+ break;
+
+ // Fill blocks with 4 colors
+ case 0xc0:
+ colorA = stream->readUint16BE();
+ case 0x20:
+ colorB = stream->readUint16BE();
+
+ // Sort out the colors
+ color4[0] = colorB;
+ color4[1] = 0;
+ color4[2] = 0;
+ color4[3] = colorA;
+
+ // Red components
+ ta = (colorA >> 10) & 0x1F;
+ tb = (colorB >> 10) & 0x1F;
+ color4[1] |= ((11 * ta + 21 * tb) >> 5) << 10;
+ color4[2] |= ((21 * ta + 11 * tb) >> 5) << 10;
+
+ // Green components
+ ta = (colorA >> 5) & 0x1F;
+ tb = (colorB >> 5) & 0x1F;
+ color4[1] |= ((11 * ta + 21 * tb) >> 5) << 5;
+ color4[2] |= ((21 * ta + 11 * tb) >> 5) << 5;
+
+ // Blue components
+ ta = colorA & 0x1F;
+ tb = colorB & 0x1F;
+ color4[1] |= ((11 * ta + 21 * tb) >> 5);
+ color4[2] |= ((21 * ta + 11 * tb) >> 5);
+
+ while (numBlocks--) {
+ blockPtr = rowPtr + pixelPtr;
+ for (byte pixel_y = 0; pixel_y < 4; pixel_y++) {
+ byte index = stream->readByte();
+ for (byte pixel_x = 0; pixel_x < 4; pixel_x++){
+ byte idx = (index >> (2 * (3 - pixel_x))) & 0x03;
+ PUT_PIXEL(color4[idx]);
+ }
+ blockPtr += rowInc;
+ }
+ ADVANCE_BLOCK();
+ }
+ break;
+
+ // Fill block with 16 colors
+ case 0x00:
+ blockPtr = rowPtr + pixelPtr;
+ for (byte pixel_y = 0; pixel_y < 4; pixel_y++) {
+ for (byte pixel_x = 0; pixel_x < 4; pixel_x++){
+ // We already have color of upper left pixel
+ if (pixel_y != 0 || pixel_x != 0)
+ colorA = stream->readUint16BE();
+
+ PUT_PIXEL(colorA);
+ }
+ blockPtr += rowInc;
+ }
+ ADVANCE_BLOCK();
+ break;
+
+ // Unknown opcode
+ default:
+ error("Unknown opcode %02x in rpza chunk", opcode);
+ }
+ }
+
+ return _surface;
+}
+
+} // End of namespace Graphics
diff --git a/graphics/video/codecs/rpza.h b/graphics/video/codecs/rpza.h
new file mode 100644
index 0000000000..e6d32feb72
--- /dev/null
+++ b/graphics/video/codecs/rpza.h
@@ -0,0 +1,49 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef GRAPHICS_VIDEO_RPZA_H
+#define GRAPHICS_VIDEO_RPZA_H
+
+#include "graphics/pixelformat.h"
+#include "graphics/video/codecs/codec.h"
+
+namespace Graphics {
+
+class RPZADecoder : public Codec {
+public:
+ RPZADecoder(uint16 width, uint16 height);
+ ~RPZADecoder() { delete _surface; }
+
+ Surface *decodeImage(Common::SeekableReadStream *stream);
+ PixelFormat getPixelFormat() const { return _pixelFormat; }
+
+private:
+ Surface *_surface;
+ PixelFormat _pixelFormat;
+};
+
+} // End of namespace Graphics
+
+#endif
diff --git a/graphics/video/codecs/smc.cpp b/graphics/video/codecs/smc.cpp
new file mode 100644
index 0000000000..4661e3dc84
--- /dev/null
+++ b/graphics/video/codecs/smc.cpp
@@ -0,0 +1,385 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+// Based off ffmpeg's SMC decoder
+
+#include "graphics/video/codecs/smc.h"
+
+namespace Graphics {
+
+#define GET_BLOCK_COUNT() \
+ (opcode & 0x10) ? (1 + stream->readByte()) : 1 + (opcode & 0x0F);
+
+#define ADVANCE_BLOCK() \
+{ \
+ pixelPtr += 4; \
+ if (pixelPtr >= _surface->w) { \
+ pixelPtr = 0; \
+ rowPtr += _surface->w * 4; \
+ } \
+ totalBlocks--; \
+ if (totalBlocks < 0) { \
+ warning("block counter just went negative (this should not happen)"); \
+ return _surface; \
+ } \
+}
+
+SMCDecoder::SMCDecoder(uint16 width, uint16 height) {
+ _surface = new Graphics::Surface();
+ _surface->create(width, height, 1);
+}
+
+Graphics::Surface *SMCDecoder::decodeImage(Common::SeekableReadStream *stream) {
+ byte *pixels = (byte *)_surface->pixels;
+
+ uint32 numBlocks = 0;
+ uint32 colorFlags = 0;
+ uint32 colorFlagsA = 0;
+ uint32 colorFlagsB = 0;
+
+ const uint16 rowInc = _surface->w - 4;
+ int32 rowPtr = 0;
+ int32 pixelPtr = 0;
+ uint32 blockPtr = 0;
+ uint32 prevBlockPtr = 0;
+ uint32 prevBlockPtr1 = 0, prevBlockPtr2 = 0;
+ byte prevBlockFlag = false;
+ byte pixel = 0;
+
+ uint32 colorPairIndex = 0;
+ uint32 colorQuadIndex = 0;
+ uint32 colorOctetIndex = 0;
+ uint32 colorTableIndex = 0; // indices to color pair, quad, or octet tables
+
+ int32 chunkSize = stream->readUint32BE() & 0x00FFFFFF;
+ if (chunkSize != stream->size())
+ warning("MOV chunk size != SMC chunk size (%d != %d); ignoring SMC chunk size", chunkSize, stream->size());
+
+ int32 totalBlocks = ((_surface->w + 3) / 4) * ((_surface->h + 3) / 4);
+
+ // traverse through the blocks
+ while (totalBlocks != 0) {
+ // sanity checks
+
+ // make sure stream ptr hasn't gone out of bounds
+ if (stream->pos() > stream->size()) {
+ warning("SMC decoder just went out of bounds (stream ptr = %d, chunk size = %d)", stream->pos(), stream->size());
+ return _surface;
+ }
+
+ // make sure the row pointer hasn't gone wild
+ if (rowPtr >= _surface->w * _surface->h) {
+ warning("SMC decoder just went out of bounds (row ptr = %d, size = %d)", rowPtr, _surface->w * _surface->h);
+ return _surface;
+ }
+
+ byte opcode = stream->readByte();
+
+ switch (opcode & 0xF0) {
+ // skip n blocks
+ case 0x00:
+ case 0x10:
+ numBlocks = GET_BLOCK_COUNT();
+ while (numBlocks--) {
+ ADVANCE_BLOCK();
+ }
+ break;
+
+ // repeat last block n times
+ case 0x20:
+ case 0x30:
+ numBlocks = GET_BLOCK_COUNT();
+
+ // sanity check
+ if (rowPtr == 0 && pixelPtr == 0) {
+ warning("encountered repeat block opcode (%02X) but no blocks rendered yet", opcode & 0xF0);
+ break;
+ }
+
+ // figure out where the previous block started
+ if (pixelPtr == 0)
+ prevBlockPtr1 = (rowPtr - _surface->w * 4) + _surface->w - 4;
+ else
+ prevBlockPtr1 = rowPtr + pixelPtr - 4;
+
+ while (numBlocks--) {
+ blockPtr = rowPtr + pixelPtr;
+ prevBlockPtr = prevBlockPtr1;
+ for (byte y = 0; y < 4; y++) {
+ for (byte x = 0; x < 4; x++)
+ pixels[blockPtr++] = pixels[prevBlockPtr++];
+ blockPtr += rowInc;
+ prevBlockPtr += rowInc;
+ }
+ ADVANCE_BLOCK();
+ }
+ break;
+
+ // repeat previous pair of blocks n times
+ case 0x40:
+ case 0x50:
+ numBlocks = GET_BLOCK_COUNT();
+ numBlocks *= 2;
+
+ // sanity check
+ if (rowPtr == 0 && pixelPtr < 2 * 4) {
+ warning("encountered repeat block opcode (%02X) but not enough blocks rendered yet", opcode & 0xF0);
+ break;
+ }
+
+ // figure out where the previous 2 blocks started
+ if (pixelPtr == 0)
+ prevBlockPtr1 = (rowPtr - _surface->w * 4) + _surface->w - 4 * 2;
+ else if (pixelPtr == 4)
+ prevBlockPtr1 = (rowPtr - _surface->w * 4) + rowInc;
+ else
+ prevBlockPtr1 = rowPtr + pixelPtr - 4 * 2;
+
+ if (pixelPtr == 0)
+ prevBlockPtr2 = (rowPtr - _surface->w * 4) + rowInc;
+ else
+ prevBlockPtr2 = rowPtr + pixelPtr - 4;
+
+ prevBlockFlag = 0;
+ while (numBlocks--) {
+ blockPtr = rowPtr + pixelPtr;
+
+ if (prevBlockFlag)
+ prevBlockPtr = prevBlockPtr2;
+ else
+ prevBlockPtr = prevBlockPtr1;
+
+ prevBlockFlag = !prevBlockFlag;
+
+ for (byte y = 0; y < 4; y++) {
+ for (byte x = 0; x < 4; x++)
+ pixels[blockPtr++] = pixels[prevBlockPtr++];
+
+ blockPtr += rowInc;
+ prevBlockPtr += rowInc;
+ }
+ ADVANCE_BLOCK();
+ }
+ break;
+
+ // 1-color block encoding
+ case 0x60:
+ case 0x70:
+ numBlocks = GET_BLOCK_COUNT();
+ pixel = stream->readByte();
+
+ while (numBlocks--) {
+ blockPtr = rowPtr + pixelPtr;
+ for (byte y = 0; y < 4; y++) {
+ for (byte x = 0; x < 4; x++)
+ pixels[blockPtr++] = pixel;
+
+ blockPtr += rowInc;
+ }
+ ADVANCE_BLOCK();
+ }
+ break;
+
+ // 2-color block encoding
+ case 0x80:
+ case 0x90:
+ numBlocks = (opcode & 0x0F) + 1;
+
+ // figure out which color pair to use to paint the 2-color block
+ if ((opcode & 0xF0) == 0x80) {
+ // fetch the next 2 colors from bytestream and store in next
+ // available entry in the color pair table
+ for (byte i = 0; i < CPAIR; i++) {
+ pixel = stream->readByte();
+ colorTableIndex = CPAIR * colorPairIndex + i;
+ _colorPairs[colorTableIndex] = pixel;
+ }
+
+ // this is the base index to use for this block
+ colorTableIndex = CPAIR * colorPairIndex;
+ colorPairIndex++;
+
+ // wraparound
+ if (colorPairIndex == COLORS_PER_TABLE)
+ colorPairIndex = 0;
+ } else
+ colorTableIndex = CPAIR * stream->readByte();
+
+ while (numBlocks--) {
+ colorFlags = stream->readUint16BE();
+ uint16 flagMask = 0x8000;
+ blockPtr = rowPtr + pixelPtr;
+ for (byte y = 0; y < 4; y++) {
+ for (byte x = 0; x < 4; x++) {
+ if (colorFlags & flagMask)
+ pixel = colorTableIndex + 1;
+ else
+ pixel = colorTableIndex;
+
+ flagMask >>= 1;
+ pixels[blockPtr++] = _colorPairs[pixel];
+ }
+
+ blockPtr += rowInc;
+ }
+ ADVANCE_BLOCK();
+ }
+ break;
+
+ // 4-color block encoding
+ case 0xA0:
+ case 0xB0:
+ numBlocks = (opcode & 0x0F) + 1;
+
+ // figure out which color quad to use to paint the 4-color block
+ if ((opcode & 0xF0) == 0xA0) {
+ // fetch the next 4 colors from bytestream and store in next
+ // available entry in the color quad table
+ for (byte i = 0; i < CQUAD; i++) {
+ pixel = stream->readByte();
+ colorTableIndex = CQUAD * colorQuadIndex + i;
+ _colorQuads[colorTableIndex] = pixel;
+ }
+
+ // this is the base index to use for this block
+ colorTableIndex = CQUAD * colorQuadIndex;
+ colorQuadIndex++;
+
+ // wraparound
+ if (colorQuadIndex == COLORS_PER_TABLE)
+ colorQuadIndex = 0;
+ } else
+ colorTableIndex = CQUAD * stream->readByte();
+
+ while (numBlocks--) {
+ colorFlags = stream->readUint32BE();
+
+ // flag mask actually acts as a bit shift count here
+ byte flagMask = 30;
+ blockPtr = rowPtr + pixelPtr;
+
+ for (byte y = 0; y < 4; y++) {
+ for (byte x = 0; x < 4; x++) {
+ pixel = colorTableIndex + ((colorFlags >> flagMask) & 0x03);
+ flagMask -= 2;
+ pixels[blockPtr++] = _colorQuads[pixel];
+ }
+ blockPtr += rowInc;
+ }
+ ADVANCE_BLOCK();
+ }
+ break;
+
+ // 8-color block encoding
+ case 0xC0:
+ case 0xD0:
+ numBlocks = (opcode & 0x0F) + 1;
+
+ // figure out which color octet to use to paint the 8-color block
+ if ((opcode & 0xF0) == 0xC0) {
+ // fetch the next 8 colors from bytestream and store in next
+ // available entry in the color octet table
+ for (byte i = 0; i < COCTET; i++) {
+ pixel = stream->readByte();
+ colorTableIndex = COCTET * colorOctetIndex + i;
+ _colorOctets[colorTableIndex] = pixel;
+ }
+
+ // this is the base index to use for this block
+ colorTableIndex = COCTET * colorOctetIndex;
+ colorOctetIndex++;
+
+ // wraparound
+ if (colorOctetIndex == COLORS_PER_TABLE)
+ colorOctetIndex = 0;
+ } else
+ colorTableIndex = COCTET * stream->readByte();
+
+ while (numBlocks--) {
+ /*
+ For this input of 6 hex bytes:
+ 01 23 45 67 89 AB
+ Mangle it to this output:
+ flags_a = xx012456, flags_b = xx89A37B
+ */
+
+ // build the color flags
+ byte flagData[6];
+ stream->read(flagData, 6);
+
+ colorFlagsA = ((READ_BE_UINT16(flagData) & 0xFFF0) << 8) | (READ_BE_UINT16(flagData + 2) >> 4);
+ colorFlagsB = ((READ_BE_UINT16(flagData + 4) & 0xFFF0) << 8) | ((flagData[1] & 0xF) << 8) |
+ ((flagData[3] & 0xF) << 4) | (flagData[5] & 0xf);
+
+ colorFlags = colorFlagsA;
+
+ // flag mask actually acts as a bit shift count here
+ byte flagMask = 21;
+ blockPtr = rowPtr + pixelPtr;
+ for (byte y = 0; y < 4; y++) {
+ // reload flags at third row (iteration y == 2)
+ if (y == 2) {
+ colorFlags = colorFlagsB;
+ flagMask = 21;
+ }
+
+ for (byte x = 0; x < 4; x++) {
+ pixel = colorTableIndex + ((colorFlags >> flagMask) & 0x07);
+ flagMask -= 3;
+ pixels[blockPtr++] = _colorOctets[pixel];
+ }
+
+ blockPtr += rowInc;
+ }
+ ADVANCE_BLOCK();
+ }
+ break;
+
+ // 16-color block encoding (every pixel is a different color)
+ case 0xE0:
+ numBlocks = (opcode & 0x0F) + 1;
+
+ while (numBlocks--) {
+ blockPtr = rowPtr + pixelPtr;
+ for (byte y = 0; y < 4; y++) {
+ for (byte x = 0; x < 4; x++)
+ pixels[blockPtr++] = stream->readByte();
+
+ blockPtr += rowInc;
+ }
+ ADVANCE_BLOCK();
+ }
+ break;
+
+ case 0xF0:
+ warning("0xF0 opcode seen in SMC chunk (contact the developers)");
+ break;
+ }
+ }
+
+ return _surface;
+}
+
+} // End of namespace Graphics
diff --git a/graphics/video/codecs/smc.h b/graphics/video/codecs/smc.h
new file mode 100644
index 0000000000..2d4355a83e
--- /dev/null
+++ b/graphics/video/codecs/smc.h
@@ -0,0 +1,59 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef GRAPHICS_VIDEO_SMC_H
+#define GRAPHICS_VIDEO_SMC_H
+
+#include "graphics/video/codecs/codec.h"
+
+namespace Graphics {
+
+enum {
+ CPAIR = 2,
+ CQUAD = 4,
+ COCTET = 8,
+ COLORS_PER_TABLE = 256
+};
+
+class SMCDecoder : public Codec {
+public:
+ SMCDecoder(uint16 width, uint16 height);
+ ~SMCDecoder() { delete _surface; }
+
+ Surface *decodeImage(Common::SeekableReadStream *stream);
+ PixelFormat getPixelFormat() const { return PixelFormat::createFormatCLUT8(); }
+
+private:
+ Surface *_surface;
+
+ // SMC color tables
+ byte _colorPairs[COLORS_PER_TABLE * CPAIR];
+ byte _colorQuads[COLORS_PER_TABLE * CQUAD];
+ byte _colorOctets[COLORS_PER_TABLE * COCTET];
+};
+
+} // End of namespace Graphics
+
+#endif