[Scummvm-git-logs] scummvm master -> 818e68174653e73492456ad98c4cee5b5eff22e3

sev- sev at scummvm.org
Mon May 11 05:54:28 UTC 2020


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
818e681746 IMAGE: Add support for Crusader: No Remorse  movie decoding


Commit: 818e68174653e73492456ad98c4cee5b5eff22e3
    https://github.com/scummvm/scummvm/commit/818e68174653e73492456ad98c4cee5b5eff22e3
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-05-11T07:54:24+02:00

Commit Message:
IMAGE: Add support for Crusader: No Remorse  movie decoding

The movies for Crusader: No Remorse have a unique decoder which is not too hard
to implement.  Unfortunately, they don't properly implement the "compression"
FourCC, and instead put their ID in the "Stream Handler".  Since supporting
them requires a change to the existing Image API, I thought I should make a
pull request for comments.

With this change, the movies in Crusader can all be played nicely.

Changed paths:
  A image/codecs/jyv1.cpp
  A image/codecs/jyv1.h
    engines/director/images.cpp
    image/bmp.cpp
    image/codecs/codec.cpp
    image/codecs/codec.h
    image/module.mk
    video/avi_decoder.cpp


diff --git a/engines/director/images.cpp b/engines/director/images.cpp
index 97ef18da69..56b3480d51 100644
--- a/engines/director/images.cpp
+++ b/engines/director/images.cpp
@@ -89,7 +89,7 @@ bool DIBDecoder::loadStream(Common::SeekableReadStream &stream) {
 
 	Common::SeekableSubReadStream subStream(&stream, 40, stream.size());
 
-	_codec = Image::createBitmapCodec(compression, width, height, bitsPerPixel);
+	_codec = Image::createBitmapCodec(compression, 0, width, height, bitsPerPixel);
 
 	if (!_codec)
 		return false;
diff --git a/image/bmp.cpp b/image/bmp.cpp
index 234b57659c..2a00cbc9d6 100644
--- a/image/bmp.cpp
+++ b/image/bmp.cpp
@@ -115,7 +115,7 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) {
 	}
 
 	// Create the codec (it will warn about unhandled compression)
-	_codec = createBitmapCodec(compression, width, height, bitsPerPixel);
+	_codec = createBitmapCodec(compression, 0, width, height, bitsPerPixel);
 	if (!_codec)
 		return false;
 
diff --git a/image/codecs/codec.cpp b/image/codecs/codec.cpp
index 048d52dc86..fdd7e98de4 100644
--- a/image/codecs/codec.cpp
+++ b/image/codecs/codec.cpp
@@ -32,6 +32,7 @@
 #include "image/codecs/indeo3.h"
 #include "image/codecs/indeo4.h"
 #include "image/codecs/indeo5.h"
+#include "image/codecs/jyv1.h"
 #include "image/codecs/mjpeg.h"
 #include "image/codecs/mpeg.h"
 #include "image/codecs/msvideo1.h"
@@ -195,7 +196,14 @@ byte *Codec::createQuickTimeDitherTable(const byte *palette, uint colorCount) {
 	return buf;
 }
 
-Codec *createBitmapCodec(uint32 tag, int width, int height, int bitsPerPixel) {
+Codec *createBitmapCodec(uint32 tag, uint32 streamTag, int width, int height, int bitsPerPixel) {
+	// Crusader videos are special cased here because the frame type is not in the "compression"
+	// tag but in the "stream handler" tag for these files
+	if (JYV1Decoder::isJYV1StreamTag(streamTag)) {
+		assert(bitsPerPixel == 8);
+		return new JYV1Decoder(width, height, streamTag);
+	}
+
 	switch (tag) {
 	case SWAP_CONSTANT_32(0):
 		return new BitmapRawDecoder(width, height, bitsPerPixel);
diff --git a/image/codecs/codec.h b/image/codecs/codec.h
index 5c072132d3..13267c2aef 100644
--- a/image/codecs/codec.h
+++ b/image/codecs/codec.h
@@ -118,9 +118,9 @@ public:
 };
 
 /**
- * Create a codec given a bitmap/AVI compression tag.
+ * Create a codec given a bitmap/AVI compression tag and stream handler tag (can be 0)
  */
-Codec *createBitmapCodec(uint32 tag, int width, int height, int bitsPerPixel);
+Codec *createBitmapCodec(uint32 tag, uint32 streamTag, int width, int height, int bitsPerPixel);
 
 /**
  * Create a codec given a QuickTime compression tag.
diff --git a/image/codecs/jyv1.cpp b/image/codecs/jyv1.cpp
new file mode 100644
index 0000000000..6c4423d1b5
--- /dev/null
+++ b/image/codecs/jyv1.cpp
@@ -0,0 +1,154 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "image/codecs/jyv1.h"
+
+#include "common/stream.h"
+#include "common/bitstream.h"
+#include "common/memstream.h"
+#include "common/util.h"
+#include "common/textconsole.h"
+#include "common/system.h"
+#include "common/debug.h"
+#include "graphics/surface.h"
+
+#define ID_JYV1 MKTAG('J','Y','V','1')
+#define ID_RRV1 MKTAG('R','R','V','1')
+#define ID_RRV2 MKTAG('R','R','V','2')
+
+namespace Image {
+
+/*static*/
+bool JYV1Decoder::isJYV1StreamTag(uint32 streamTag) {
+	return (streamTag == ID_JYV1 || streamTag == ID_RRV1 || streamTag == ID_RRV2);
+}
+
+JYV1Decoder::JYV1Decoder(int width, int height, uint32 streamTag) : Codec(),
+		_width(width), _height(height), _streamType(streamTag) {
+	assert(isJYV1StreamTag(streamTag));
+	_surface.create(_width, _height, getPixelFormat());
+}
+
+JYV1Decoder::~JYV1Decoder() {
+	_surface.free();
+}
+
+static const uint32 BASE_LEN[] = {0, 1 << 7, 1 << 3, 0, 1 << 1, 0, 1 << 5, 0,
+								  1, 1 << 8, 1 << 4, 0, 1 << 2, 0, 1 << 6, 0};
+static const uint32 FINE_LEN_BITS[] = {0, 7, 3, 0, 1, 16, 5, 0,
+									   1, 8, 4, 0, 2, 24, 6, 0};
+
+/**
+ * Details of this decoding algorithm are here:
+ * https://wiki.multimedia.cx/index.php/Origin_Flic_Codec
+ */
+const Graphics::Surface *JYV1Decoder::decodeFrame(Common::SeekableReadStream &stream) {
+
+	byte *dst = (byte *)_surface.getPixels();
+
+	uint32 offsets[16]; // RRV2 has 15 block offsets, others have 5
+	const int numOffsets = (_streamType == ID_RRV2 ? 15 : 5);
+	const int blockHeight = _height / numOffsets;
+	const int startOffset = stream.pos();
+
+	// Read in the block offsets and convert to stream offsets
+	for (int i = 0; i < numOffsets; i++) {
+		offsets[i] = stream.readUint32LE() + startOffset;
+	}
+
+	int y = 0;
+	int x = 0;
+	bool upscale = false;
+	for (int i = 0; i < numOffsets; i++) {
+		stream.seek(offsets[i], SEEK_SET);
+		const int cmdLen = stream.readUint32LE();
+
+		// TODO: can probably avoid this copy to make it faster
+		uint8 *cmdData = new uint8[cmdLen];
+		stream.read(cmdData, cmdLen);
+		Common::BitStreamMemoryStream cmdMemStream(cmdData, cmdLen);
+		Common::BitStreamMemory8MSB cmdBitStream(cmdMemStream);
+		bool skipping = true;
+		while (!cmdBitStream.eos()) {
+			uint32 idx = cmdBitStream.getBits(4);
+			uint32 blocksize = BASE_LEN[idx];
+			if (idx != 0 and idx != 8) {
+			   blocksize += cmdBitStream.getBits(FINE_LEN_BITS[idx]);
+			}
+			if (skipping) {
+				// leave blocksize pixels unchanged
+				if (upscale)
+					blocksize *= 2;
+
+				while (blocksize) {
+					blocksize--;
+					x++;
+					if (x == _width) {
+						x = 0;
+						y++;
+					}
+				}
+			} else {
+				// draw blocksize pixels from data block
+				while (blocksize) {
+					// TODO: would be nicer to read these in whole scanlines.
+					// Also this upscale code is kinda ugly.
+					const uint8 p = stream.readByte();
+					dst[y * _width + x] = p;
+					x++;
+					if (x == _width) {
+						x = 0;
+						y++;
+					}
+					if (upscale) {
+						dst[y * _width + x] = p;
+						x++;
+						if (x == _width) {
+							x = 0;
+							y++;
+						}
+					}
+					blocksize--;
+				}
+			}
+			skipping = !skipping;
+		}
+
+		// Slight HACK - if we only used half the expected height, then
+		// this frame should be upscaled.  Go back and do it again.
+		if (!upscale && y == blockHeight / 2) {
+			y = 0;
+			i--;
+			upscale = true;
+		}
+
+		delete [] cmdData;
+
+	}
+	return &_surface;
+}
+
+Graphics::PixelFormat JYV1Decoder::getPixelFormat() const {
+	return Graphics::PixelFormat::createFormatCLUT8();
+}
+
+} // End of namespace Image
diff --git a/image/codecs/jyv1.h b/image/codecs/jyv1.h
new file mode 100644
index 0000000000..ec4ee1306b
--- /dev/null
+++ b/image/codecs/jyv1.h
@@ -0,0 +1,53 @@
+/* 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 IMAGE_CODECS_JYV1_H
+#define IMAGE_CODECS_JYV1_H
+
+#include "image/codecs/codec.h"
+
+namespace Image {
+
+/**
+ * JYV1/RRV1/RRV2 image decoder.
+ *
+ * Used by Crusader: No Remorse AVI files
+ */
+class JYV1Decoder : public Codec {
+public:
+	JYV1Decoder (int width, int height, uint32 streamTag);
+	~JYV1Decoder();
+
+	const Graphics::Surface *decodeFrame(Common::SeekableReadStream &stream) override;
+	Graphics::PixelFormat getPixelFormat() const override;
+
+	static bool isJYV1StreamTag(uint32 streamTag);
+
+private:
+	Graphics::Surface _surface;
+	int _width, _height;
+	uint32 _streamType;
+};
+
+} // End of namespace Image
+
+#endif
diff --git a/image/module.mk b/image/module.mk
index be049eb818..21566dd602 100644
--- a/image/module.mk
+++ b/image/module.mk
@@ -15,6 +15,7 @@ MODULE_OBJS := \
 	codecs/indeo3.o \
 	codecs/indeo4.o \
 	codecs/indeo5.o \
+	codecs/jyv1.o \
 	codecs/mjpeg.o \
 	codecs/msrle.o \
 	codecs/msrle4.o \
diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp
index a42c8e28c6..4f54b82f85 100644
--- a/video/avi_decoder.cpp
+++ b/video/avi_decoder.cpp
@@ -201,6 +201,7 @@ bool AVIDecoder::parseNextChunk() {
 	case ID_STRH:
 		handleStreamHeader(size);
 		break;
+	case ID_HDRL: // Header list.. what's it doing here? Probably ok to ignore?
 	case ID_STRD: // Extra stream info, safe to ignore
 	case ID_VEDT: // Unknown, safe to ignore
 	case ID_JUNK: // Alignment bytes, should be ignored
@@ -990,7 +991,8 @@ bool AVIDecoder::AVIVideoTrack::rewind() {
 }
 
 Image::Codec *AVIDecoder::AVIVideoTrack::createCodec() {
-	return Image::createBitmapCodec(_bmInfo.compression, _bmInfo.width, _bmInfo.height, _bmInfo.bitCount);
+	return Image::createBitmapCodec(_bmInfo.compression, _vidsHeader.streamHandler, _bmInfo.width,
+									_bmInfo.height, _bmInfo.bitCount);
 }
 
 void AVIDecoder::AVIVideoTrack::forceTrackEnd() {




More information about the Scummvm-git-logs mailing list