[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