[Scummvm-git-logs] scummvm master -> 9a31a8926ccc36853a13150ec3469f7325da9512

bluegr bluegr at gmail.com
Sat Apr 17 18:51:55 UTC 2021


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

Summary:
d9fe53efb2 CRYOMNI3D: Move HNMDecoder into common code
d38567bfd9 VIDEO: Support decoding older HNMv4 variants
46e696d417 CRYO: Use the common HNM decoder
f1e90ada2f VIDEO: Optimize HNM4 decoding slightly
0953a690f4 VIDEO: Fix HNM decoding
bf7ddf6a70 VIDEO: HNM Postprocessing simplification
9a31a8926c VIDEO: HNM channels attribute is not channels but some kind of format


Commit: d9fe53efb2d5a6ae9a9afd7c6ecd1b07d30fb91f
    https://github.com/scummvm/scummvm/commit/d9fe53efb2d5a6ae9a9afd7c6ecd1b07d30fb91f
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2021-04-17T21:48:45+03:00

Commit Message:
CRYOMNI3D: Move HNMDecoder into common code

Changed paths:
  A image/codecs/hlz.cpp
  A image/codecs/hlz.h
  A video/hnm_decoder.cpp
  A video/hnm_decoder.h
  R engines/cryomni3d/image/codecs/hlz.cpp
  R engines/cryomni3d/image/codecs/hlz.h
  R engines/cryomni3d/video/hnm_decoder.cpp
  R engines/cryomni3d/video/hnm_decoder.h
    engines/cryomni3d/cryomni3d.cpp
    engines/cryomni3d/image/hlz.cpp
    engines/cryomni3d/module.mk
    engines/cryomni3d/versailles/dialogs_manager.cpp
    image/module.mk
    video/module.mk


diff --git a/engines/cryomni3d/cryomni3d.cpp b/engines/cryomni3d/cryomni3d.cpp
index 484063d915..0d7a173d2e 100644
--- a/engines/cryomni3d/cryomni3d.cpp
+++ b/engines/cryomni3d/cryomni3d.cpp
@@ -36,7 +36,7 @@
 #include "cryomni3d/datstream.h"
 
 #include "cryomni3d/image/hlz.h"
-#include "cryomni3d/video/hnm_decoder.h"
+#include "video/hnm_decoder.h"
 
 namespace CryOmni3D {
 
diff --git a/engines/cryomni3d/image/hlz.cpp b/engines/cryomni3d/image/hlz.cpp
index dd545c5056..a9bf0dcfbc 100644
--- a/engines/cryomni3d/image/hlz.cpp
+++ b/engines/cryomni3d/image/hlz.cpp
@@ -29,7 +29,7 @@
 #include "graphics/surface.h"
 #include "image/codecs/codec.h"
 
-#include "cryomni3d/image/codecs/hlz.h"
+#include "image/codecs/hlz.h"
 
 namespace Image {
 
diff --git a/engines/cryomni3d/module.mk b/engines/cryomni3d/module.mk
index 2b8ed9dc7e..9d2c7ded04 100644
--- a/engines/cryomni3d/module.mk
+++ b/engines/cryomni3d/module.mk
@@ -3,9 +3,7 @@ MODULE := engines/cryomni3d
 MODULE_OBJS = \
 	fonts/cryoextfont.o \
 	fonts/cryofont.o \
-	image/codecs/hlz.o \
 	image/hlz.o \
-	video/hnm_decoder.o \
 	cryomni3d.o \
 	datstream.o \
 	dialogs_manager.o \
diff --git a/engines/cryomni3d/versailles/dialogs_manager.cpp b/engines/cryomni3d/versailles/dialogs_manager.cpp
index f8ede020a1..8558ad81e7 100644
--- a/engines/cryomni3d/versailles/dialogs_manager.cpp
+++ b/engines/cryomni3d/versailles/dialogs_manager.cpp
@@ -24,7 +24,7 @@
 #include "common/file.h"
 #include "common/system.h"
 
-#include "cryomni3d/video/hnm_decoder.h"
+#include "video/hnm_decoder.h"
 
 #include "cryomni3d/versailles/dialogs_manager.h"
 #include "cryomni3d/versailles/engine.h"
diff --git a/engines/cryomni3d/image/codecs/hlz.cpp b/image/codecs/hlz.cpp
similarity index 98%
rename from engines/cryomni3d/image/codecs/hlz.cpp
rename to image/codecs/hlz.cpp
index 754c0cc0ca..943c61ce33 100644
--- a/engines/cryomni3d/image/codecs/hlz.cpp
+++ b/image/codecs/hlz.cpp
@@ -20,7 +20,7 @@
  *
  */
 
-#include "cryomni3d/image/codecs/hlz.h"
+#include "image/codecs/hlz.h"
 
 #include "common/stream.h"
 #include "common/textconsole.h"
diff --git a/engines/cryomni3d/image/codecs/hlz.h b/image/codecs/hlz.h
similarity index 95%
rename from engines/cryomni3d/image/codecs/hlz.h
rename to image/codecs/hlz.h
index 680a6ad404..ffa75c1c9c 100644
--- a/engines/cryomni3d/image/codecs/hlz.h
+++ b/image/codecs/hlz.h
@@ -20,8 +20,8 @@
  *
  */
 
-#ifndef CRYOMNI3D_IMAGE_CODECS_HLZ_H
-#define CRYOMNI3D_IMAGE_CODECS_HLZ_H
+#ifndef IMAGE_CODECS_HLZ_H
+#define IMAGE_CODECS_HLZ_H
 
 #include "image/codecs/codec.h"
 
diff --git a/image/module.mk b/image/module.mk
index c3a4535b29..1cfff5c405 100644
--- a/image/module.mk
+++ b/image/module.mk
@@ -14,6 +14,7 @@ MODULE_OBJS := \
 	codecs/cdtoons.o \
 	codecs/cinepak.o \
 	codecs/codec.o \
+	codecs/hlz.o \
 	codecs/indeo3.o \
 	codecs/indeo4.o \
 	codecs/indeo5.o \
diff --git a/engines/cryomni3d/video/hnm_decoder.cpp b/video/hnm_decoder.cpp
similarity index 99%
rename from engines/cryomni3d/video/hnm_decoder.cpp
rename to video/hnm_decoder.cpp
index 5214cfd8e2..24f6c28f57 100644
--- a/engines/cryomni3d/video/hnm_decoder.cpp
+++ b/video/hnm_decoder.cpp
@@ -29,8 +29,8 @@
 
 #include "audio/decoders/raw.h"
 
-#include "cryomni3d/video/hnm_decoder.h"
-#include "cryomni3d/image/codecs/hlz.h"
+#include "video/hnm_decoder.h"
+#include "image/codecs/hlz.h"
 
 namespace Video {
 
diff --git a/engines/cryomni3d/video/hnm_decoder.h b/video/hnm_decoder.h
similarity index 98%
rename from engines/cryomni3d/video/hnm_decoder.h
rename to video/hnm_decoder.h
index 9a569ba9ea..b389dd9763 100644
--- a/engines/cryomni3d/video/hnm_decoder.h
+++ b/video/hnm_decoder.h
@@ -20,8 +20,8 @@
  *
  */
 
-#ifndef CRYOMNI3D_VIDEO_HNM_DECODER_H
-#define CRYOMNI3D_VIDEO_HNM_DECODER_H
+#ifndef VIDEO_HNM_DECODER_H
+#define VIDEO_HNM_DECODER_H
 
 #include "common/rational.h"
 #include "graphics/pixelformat.h"
diff --git a/video/module.mk b/video/module.mk
index 875b141672..8f6ce8af83 100644
--- a/video/module.mk
+++ b/video/module.mk
@@ -6,6 +6,7 @@ MODULE_OBJS := \
 	coktel_decoder.o \
 	dxa_decoder.o \
 	flic_decoder.o \
+	hnm_decoder.o \
 	mpegps_decoder.o \
 	mve_decoder.o \
 	psx_decoder.o \


Commit: d38567bfd904adce3750d2bf2d7faee227eb6024
    https://github.com/scummvm/scummvm/commit/d38567bfd904adce3750d2bf2d7faee227eb6024
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2021-04-17T21:48:46+03:00

Commit Message:
VIDEO: Support decoding older HNMv4 variants

Changed paths:
    video/hnm_decoder.cpp
    video/hnm_decoder.h


diff --git a/video/hnm_decoder.cpp b/video/hnm_decoder.cpp
index 24f6c28f57..e9465fe0a9 100644
--- a/video/hnm_decoder.cpp
+++ b/video/hnm_decoder.cpp
@@ -127,16 +127,19 @@ void HNMDecoder::readNextPacket() {
 	while (superchunkRemaining) {
 		uint32 chunkSize = _stream->readUint32LE();
 		uint16 chunkType = _stream->readUint16BE();
-		//uint16 ukn        = _stream->readUint16LE();
-		_stream->skip(2);
+		uint16 flags     = _stream->readUint16LE();
 
 		if (chunkType == MKTAG16('P', 'L')) {
 			_videoTrack->decodePalette(_stream, chunkSize - 8);
 		} else if (chunkType == MKTAG16('I', 'Z')) {
 			_stream->skip(4);
-			_videoTrack->decodeIntraframe(_stream, chunkSize - 8 - 4);
+			_videoTrack->decodeIntraframe(_stream, chunkSize - 8 - 4, flags);
 		} else if (chunkType == MKTAG16('I', 'U')) {
-			_videoTrack->decodeInterframe(_stream, chunkSize - 8);
+			if ((flags & 1) == 1) {
+				_videoTrack->decodeInterframeA(_stream, chunkSize - 8, flags);
+			} else {
+				_videoTrack->decodeInterframe(_stream, chunkSize - 8, flags);
+			}
 		} else if (chunkType == MKTAG16('S', 'D')) {
 			if (_audioTrack) {
 				Audio::Timestamp duration = _audioTrack->decodeSound(_stream, chunkSize - 8);
@@ -167,21 +170,25 @@ HNMDecoder::HNM4VideoTrack::HNM4VideoTrack(uint32 width, uint32 height, uint32 f
 	}
 	_dirtyPalette = true;
 
-	if (width * height != frameSize) {
-		error("Invalid frameSize");
+	if (width * height > frameSize) {
+		error("Invalid frameSize: expected %d, got %d", width * height, frameSize);
 	}
 
-	// We will use _frameBufferC/P as the surface pixels, just init there with nullptr to avoid unintended usage of surface
-	const Graphics::PixelFormat &f = Graphics::PixelFormat::createFormatCLUT8();
-	_surface.init(width, height, width * f.bytesPerPixel, nullptr, f);
+	_frameBufferF = new byte[frameSize];
+	memset(_frameBufferF, 0, frameSize);
 	_frameBufferC = new byte[frameSize];
 	memset(_frameBufferC, 0, frameSize);
 	_frameBufferP = new byte[frameSize];
 	memset(_frameBufferP, 0, frameSize);
+
+	const Graphics::PixelFormat &f = Graphics::PixelFormat::createFormatCLUT8();
+	_surface.init(width, height, width * f.bytesPerPixel, _frameBufferF, f);
 }
 
 HNMDecoder::HNM4VideoTrack::~HNM4VideoTrack() {
 	// Don't free _surface as we didn't used create() but init()
+	delete[] _frameBufferF;
+	_frameBufferF = nullptr;
 	delete[] _frameBufferC;
 	_frameBufferC = nullptr;
 	delete[] _frameBufferP;
@@ -240,7 +247,129 @@ void HNMDecoder::HNM4VideoTrack::decodePalette(Common::SeekableReadStream *strea
 	}
 }
 
-void HNMDecoder::HNM4VideoTrack::decodeInterframe(Common::SeekableReadStream *stream, uint32 size) {
+void HNMDecoder::HNM4VideoTrack::decodeInterframe(Common::SeekableReadStream *stream, uint32 size, uint16 flags) {
+	SWAP(_frameBufferC, _frameBufferP);
+
+	uint16 width = _surface.w;
+	bool eop = false;
+
+	uint currentPos = 0;
+
+	while (!eop) {
+		if (size < 1) {
+			warning("Not enough data in chunk for interframe block");
+			break;
+		}
+		byte countFlgs = stream->readByte();
+		size -= 1;
+		byte count = countFlgs & 0x1f;
+		byte flgs = (countFlgs >> 5) & 0x7;
+
+		if (count == 0) {
+			int c, fill;
+			switch (flgs) {
+			case 0:
+				if (size < 2) {
+					error("Not enough data for case 0");
+				}
+				// Copy next two bytes of input to the output
+				c = stream->readByte();
+				_frameBufferC[currentPos++] = c;
+				c = stream->readByte();
+				_frameBufferC[currentPos++] = c;
+				size -= 2;
+				break;
+			case 1:
+				if (size < 1) {
+					error("Not enough data for case 1");
+				}
+				// Skip (next byte of input) * 2 bytes of output
+				c = stream->readByte() * 2;
+				currentPos += c;
+				size -= 1;
+				break;
+			case 2:
+				if (size < 2) {
+					error("Not enough data for case 2");
+				}
+				// Skip (next word of input) * 2 bytes of output
+				c = stream->readUint16LE() * 2;
+				currentPos += c;
+				size -= 2;
+				break;
+			case 3:
+				if (size < 2) {
+					error("Not enough data for case 3");
+				}
+				// Fill (next byte of input) * 2 of output with (next byte of input)
+				c = stream->readByte() * 2;
+				fill = stream->readByte();
+				while (c--) {
+					_frameBufferC[currentPos++] = fill;
+				}
+				size -= 2;
+				break;
+			default:
+				// End of picture
+				eop = true;
+				break;
+			}
+		} else {
+			if (size < 2) {
+				error("Not enough data for count > 0");
+			}
+
+			bool backward = (flgs & 0x4) != 0;
+			bool backline = (flgs & 0x2) != 0;
+			bool previous = (flgs & 0x1) != 0;
+			int offset = stream->readUint16LE();
+			bool swap = (offset & 0x1) != 0;
+			size -= 2;
+
+			offset = currentPos + (offset & 0xFFFE) - 0x8000;
+			if (offset < 0) {
+				error("Invalid offset");
+			}
+
+			byte *ptr;
+			if (previous) {
+				ptr = _frameBufferP;
+			} else {
+				ptr = _frameBufferC;
+			}
+
+			int shft1, shft2;
+			if (backline) {
+				const int twolinesabove = -(width * 2);
+				shft1 = twolinesabove + 1;
+				shft2 = 0;
+			} else {
+				shft1 = 0;
+				shft2 = 1;
+			}
+			if (swap)
+				SWAP(shft1, shft2);
+
+			while (count--) {
+				_frameBufferC[currentPos++] = ptr[offset + shft1];
+				_frameBufferC[currentPos++] = ptr[offset + shft2];
+				offset += backward ? -2 : 2;
+			}
+		}
+	}
+	postprocess(flags);
+
+	_curFrame++;
+	_nextFrameStartTime += _nextFrameDelay != uint32(-1) ? _nextFrameDelay : _regularFrameDelay;
+	_nextFrameDelay = _nextNextFrameDelay;
+	_nextNextFrameDelay = uint32(-1);
+
+	if (size > 0) {
+		stream->skip(size);
+	}
+}
+
+void HNMDecoder::HNM4VideoTrack::decodeInterframeA(Common::SeekableReadStream *stream, uint32 size, uint16 flags) {
 	SWAP(_frameBufferC, _frameBufferP);
 
 	uint16 width = _surface.w;
@@ -326,7 +455,7 @@ void HNMDecoder::HNM4VideoTrack::decodeInterframe(Common::SeekableReadStream *st
 			}
 		}
 	}
-	_surface.setPixels(_frameBufferC);
+	postprocess(flags);
 
 	_curFrame++;
 	_nextFrameStartTime += _nextFrameDelay != uint32(-1) ? _nextFrameDelay : _regularFrameDelay;
@@ -338,10 +467,10 @@ void HNMDecoder::HNM4VideoTrack::decodeInterframe(Common::SeekableReadStream *st
 	}
 }
 
-void HNMDecoder::HNM4VideoTrack::decodeIntraframe(Common::SeekableReadStream *stream, uint32 size) {
+void HNMDecoder::HNM4VideoTrack::decodeIntraframe(Common::SeekableReadStream *stream, uint32 size, uint16 flags) {
 	Image::HLZDecoder::decodeFrameInPlace(*stream, size, _frameBufferC);
 	memcpy(_frameBufferP, _frameBufferC, (uint)_surface.w * (uint)_surface.h);
-	_surface.setPixels(_frameBufferC);
+	postprocess(flags);
 
 	_curFrame++;
 	_nextFrameStartTime += _nextFrameDelay != uint32(-1) ? _nextFrameDelay : _regularFrameDelay;
@@ -349,6 +478,40 @@ void HNMDecoder::HNM4VideoTrack::decodeIntraframe(Common::SeekableReadStream *st
 	_nextNextFrameDelay = uint32(-1);
 }
 
+void HNMDecoder::HNM4VideoTrack::postprocess(uint16 flags) {
+	int width = _surface.w;
+	int height = _surface.h;
+
+	if ((flags & 1) == 1) {
+		memcpy(_frameBufferF, _frameBufferC, width * height);
+	} else if ((width % 4) == 0) {
+		byte *input = _frameBufferC;
+		byte *line0 = _frameBufferF;
+		byte *line1 = _frameBufferF + width;
+		int count = (height) / 2;
+		while (count--) {
+			int16 i;
+			for (i = 0; i < width / 4; i++) {
+				byte p0 = *input++, p1 = *input++, p2 = *input++, p3 = *input++;
+				byte p4 = *input++, p5 = *input++, p6 = *input++, p7 = *input++;
+
+				*line0++ = p0;
+				*line0++ = p2;
+				*line0++ = p4;
+				*line0++ = p6;
+				*line1++ = p1;
+				*line1++ = p3;
+				*line1++ = p5;
+				*line1++ = p7;
+			}
+			line0 += width;
+			line1 += width;
+		}
+	} else {
+		error("HNMDecoder::HNM4VideoTrack::postprocess(%x): Unexpected width: %d", flags, width);
+	}
+}
+
 HNMDecoder::DPCMAudioTrack::DPCMAudioTrack(uint16 channels, uint16 bits, uint sampleRate,
 		Audio::Mixer::SoundType soundType) : AudioTrack(soundType), _audioStream(nullptr),
 	_gotLUT(false), _lastSample(0) {
diff --git a/video/hnm_decoder.h b/video/hnm_decoder.h
index b389dd9763..5752f803de 100644
--- a/video/hnm_decoder.h
+++ b/video/hnm_decoder.h
@@ -72,8 +72,10 @@ private:
 
 		/** Decode a video chunk. */
 		void decodePalette(Common::SeekableReadStream *stream, uint32 size);
-		void decodeInterframe(Common::SeekableReadStream *stream, uint32 size);
-		void decodeIntraframe(Common::SeekableReadStream *stream, uint32 size);
+		void decodeInterframe(Common::SeekableReadStream *stream, uint32 size, uint16 flags);
+		void decodeInterframeA(Common::SeekableReadStream *stream, uint32 size, uint16 flags);
+		void decodeIntraframe(Common::SeekableReadStream *stream, uint32 size, uint16 flags);
+		void postprocess(uint16 flags);
 
 		void restart() { _nextFrameDelay = uint32(-1); _nextNextFrameDelay = uint32(-1); }
 		void setFrameDelay(uint32 frameDelay);
@@ -92,6 +94,7 @@ private:
 		byte _palette[256 * 3];
 		mutable bool _dirtyPalette;
 
+		byte *_frameBufferF;
 		byte *_frameBufferC;
 		byte *_frameBufferP;
 	};


Commit: 46e696d41714b05ef9243e2411ee18baf2fe4161
    https://github.com/scummvm/scummvm/commit/46e696d41714b05ef9243e2411ee18baf2fe4161
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2021-04-17T21:48:46+03:00

Commit Message:
CRYO: Use the common HNM decoder

Changed paths:
  R engines/cryo/video.cpp
  R engines/cryo/video.h
    engines/cryo/cryo.cpp
    engines/cryo/cryo.h
    engines/cryo/cryolib.h
    engines/cryo/eden.cpp
    engines/cryo/eden.h
    engines/cryo/eden_graphics.cpp
    engines/cryo/eden_graphics.h
    engines/cryo/module.mk
    engines/cryo/resource.cpp
    video/hnm_decoder.h


diff --git a/engines/cryo/cryo.cpp b/engines/cryo/cryo.cpp
index 92e3d52c9e..4216a21165 100644
--- a/engines/cryo/cryo.cpp
+++ b/engines/cryo/cryo.cpp
@@ -44,7 +44,6 @@ CryoEngine::CryoEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engin
 	_rnd = new Common::RandomSource("cryo");
 
 	_game = nullptr;
-	_video = nullptr;
 	_screenView = nullptr;
 
 	_showHotspots = false;
@@ -56,7 +55,6 @@ CryoEngine::CryoEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engin
 CryoEngine::~CryoEngine() {
 	delete _rnd;
 	delete _game;
-	delete _video;
 	delete _screenView;
 
 	DebugMan.clearAllDebugChannels();
@@ -64,7 +62,6 @@ CryoEngine::~CryoEngine() {
 
 Common::Error CryoEngine::run() {
 	_game = new EdenGame(this);
-	_video = new HnmPlayer(this);
 	_screenView = new View(320, 200);
 	setDebugger(new Debugger(this));
 
diff --git a/engines/cryo/cryo.h b/engines/cryo/cryo.h
index e2483686fc..b28c8014b3 100644
--- a/engines/cryo/cryo.h
+++ b/engines/cryo/cryo.h
@@ -35,7 +35,6 @@
 #include "graphics/screen.h"
 
 #include "cryo/eden.h"
-#include "cryo/video.h"
 #include "cryo/debugger.h"
 
 struct ADGameDescription;
@@ -70,7 +69,6 @@ public:
 
 	Graphics::Surface _screen;
 	EdenGame *_game;
-	HnmPlayer *_video;
 
 	View *_screenView;
 	volatile int32 _timerTicks;
diff --git a/engines/cryo/cryolib.h b/engines/cryo/cryolib.h
index 63ae29003f..ed569af550 100644
--- a/engines/cryo/cryolib.h
+++ b/engines/cryo/cryolib.h
@@ -71,14 +71,6 @@ struct color_t {
 	uint16   a, r, g, b;
 };
 
-struct HNMHeader {
-	int32   _signature;
-	uint16  _width;
-	uint16  _height;
-	int32   _numbFrame;
-	int32   _bufferSize;
-};
-
 void SysBeep(int x);
 void FlushEvents(int16 arg1, int16 arg2);
 
diff --git a/engines/cryo/eden.cpp b/engines/cryo/eden.cpp
index 212bfdc44a..5491e14ffc 100644
--- a/engines/cryo/eden.cpp
+++ b/engines/cryo/eden.cpp
@@ -112,7 +112,6 @@ EdenGame::EdenGame(CryoEngine *vm) : _vm(vm), kMaxMusicSize(2200000) {
 	_gameStarted = false;
 	_soundAllocated = false;
 	_musicChannel = _voiceChannel = nullptr;
-	_hnmSoundChannel = nullptr;
 	_cirsorPanX = 0;
 	_inventoryScrollDelay = 0;
 	_cursorPosY = _cursorPosX = 0;
@@ -211,11 +210,6 @@ void EdenGame::displayFrescoes() {
 	_paletteUpdateRequired = true;
 }
 
-void EdenGame::setVolume(uint16 vol) {
-	_hnmSoundChannel->setVolumeLeft(vol);
-	_hnmSoundChannel->setVolumeRight(vol);
-}
-
 void EdenGame::gametofresques() {
 	_frescoTalk = false;
 	_graphics->rundcurs();
@@ -4075,14 +4069,10 @@ void EdenGame::run() {
 
 	word_378CE = 0;
 	CRYOLib_ManagersInit();
-	_vm->_video->setupSound(11025, false, false);
-	_vm->_video->setForceZero2Black(true);
-	_vm->_video->setupTimer(12.5);
-	_hnmSoundChannel = _vm->_video->getSoundChannel();
 
 	_musicChannel = new CSoundChannel(_vm->_mixer, 11025, false);
 	_voiceChannel = new CSoundChannel(_vm->_mixer, 11025, false);
-	_graphics = new EdenGraphics(this,_vm->_video);
+	_graphics = new EdenGraphics(this);
 	_graphics->setSavedUnderSubtitles(false);
 
 	allocateBuffers();
@@ -4183,19 +4173,11 @@ void EdenGame::edmain() {
 void EdenGame::intro() {
 	if (_vm->getPlatform() == Common::kPlatformMacintosh) {
 		// Play intro videos in HQ
-		_hnmSoundChannel->stop();
-		_vm->_video->closeSound();
-		_vm->_video->setupSound(22050, false, true);
-		_hnmSoundChannel = _vm->_video->getSoundChannel();
 		_graphics->playHNM(2012);
 		_graphics->playHNM(171);
 		CLBlitter_FillScreenView(0);
 		_specialTextMode = false;
 		_graphics->playHNM(2001);
-		_hnmSoundChannel->stop();
-		_vm->_video->closeSound();
-		_vm->_video->setupSound(11025, false, false);
-		_hnmSoundChannel = _vm->_video->getSoundChannel();
 	} else {
 		if (_vm->isDemo()) {
 			_graphics->playHNM(171);	// Virgin logo
diff --git a/engines/cryo/eden.h b/engines/cryo/eden.h
index 5c1392f511..50b22ee069 100644
--- a/engines/cryo/eden.h
+++ b/engines/cryo/eden.h
@@ -67,15 +67,13 @@ public:
 
 	void stopMusic();
 
-	void setVolume(uint16 vol);
-
 	uint16 getMouseCenterX();
 	uint16 getMouseCenterY();
 
 	bool dialoscansvmas(Dialog *dial);
 	void musique();
 	void preloadDialogs(int16 vid);
-	void loadHnm(uint16 num);
+	Common::SeekableReadStream *loadSubStream(uint16 num);
 	bool personIsTalking();
 	bool animationIsActive();
 	byte *getImageDesc();
@@ -648,7 +646,6 @@ private:
 
 	CSoundChannel  *_musicChannel;
 	CSoundChannel  *_voiceChannel;
-	CSoundChannel *_hnmSoundChannel;
 
 	int   _demoCurrentTicks;
 	int   _demoStartTicks;
diff --git a/engines/cryo/eden_graphics.cpp b/engines/cryo/eden_graphics.cpp
index 3896a9fdbb..31b2e1b250 100644
--- a/engines/cryo/eden_graphics.cpp
+++ b/engines/cryo/eden_graphics.cpp
@@ -26,11 +26,14 @@
 #include "cryo/eden.h"
 #include "cryo/sound.h"
 #include "cryo/eden_graphics.h"
-#include "cryo/video.h"
+
+#include "graphics/conversion.h"
+#include "graphics/palette.h"
+#include "video/hnm_decoder.h"
 
 namespace Cryo {
 
-EdenGraphics::EdenGraphics(EdenGame *game, HnmPlayer *video) : _game(game), _video(video) {
+EdenGraphics::EdenGraphics(EdenGame *game) : _game(game) {
 	_glowH = _glowW = _glowY = _glowX = 0;
 	_showVideoSubtitle = false;
 	_showBlackBars = false;	
@@ -1167,21 +1170,40 @@ void EdenGraphics::effetpix() {
 
 ////// film.c
 // Original name: showfilm
-void EdenGraphics::showMovie(char arg1) {
-	_video->readHeader();
-	if (_game->_globals->_curVideoNum == 92) {
-		// _hnmContext->_header._unusedFlag2 = 0; CHECKME: Useless?
-		_game->setVolume(0);
+void EdenGraphics::showMovie(int16 num, char arg1) {
+	Common::SeekableReadStream *stream = _game->loadSubStream(num - 1 + 485);
+	if (!stream) {
+		warning("Could not load movie %d", num);
+		return;
 	}
 
-	if (_video->getVersion() != 4)
+	int16 j;
+	color_t palette16[256];
+	byte *palette = new byte[256 * 3];
+	CLPalette_GetLastPalette(palette16);
+	for (int16 i = 0; i < 256; i++) {
+		palette[j++] = palette16[i].r >> 8;
+		palette[j++] = palette16[i].g >> 8;
+		palette[j++] = palette16[i].b >> 8;
+	}
+
+	Video::VideoDecoder *decoder = new Video::HNMDecoder(false, palette);
+	if (!decoder->loadStream(stream)) {
+		warning("Could not load movie %d", num);
+		delete decoder;
+		delete stream;
 		return;
+	}
 
-	bool playing = true;
-	_video->allocMemory();
-	_hnmView = new View(_video->_header._width, _video->_header._height);
+	if (_game->_globals->_curVideoNum == 92) {
+		decoder->setVolume(0);
+	}
+
+	decoder->start();
+
+	_hnmView = new View(decoder->getWidth(), decoder->getHeight());
 	_hnmView->setSrcZoomValues(0, 0);
-	_hnmView->setDisplayZoomValues(_video->_header._width * 2, _video->_header._height * 2);
+	_hnmView->setDisplayZoomValues(decoder->getWidth() * 2, decoder->getHeight() * 2);
 	_hnmView->centerIn(_game->_vm->_screenView);
 	_hnmViewBuf = _hnmView->_bufferPtr;
 	if (arg1) {
@@ -1190,15 +1212,30 @@ void EdenGraphics::showMovie(char arg1) {
 		_hnmView->_normal._dstTop = _mainView->_normal._dstTop + 16;
 		_hnmView->_zoom._dstTop = _mainView->_zoom._dstTop + 32;
 	}
-	_video->setFinalBuffer(_hnmView->_bufferPtr);
+
 	do {
-		_hnmFrameNum = _video->getFrameNum();
-		_video->waitLoop();
-		playing = _video->nextElement();
+		if (decoder->needsUpdate()) {
+			const Graphics::Surface *frame = decoder->decodeNextFrame();
+			if (frame) {
+				Graphics::copyBlit(_hnmView->_bufferPtr, (const byte *)frame->getPixels(), _hnmView->_pitch, frame->pitch, frame->w, frame->h, 1);
+			}
+			if (decoder->hasDirtyPalette()) {
+				const byte *framePalette = decoder->getPalette();
+				for (int i = 0; i < 256; i++) {
+					palette16[i].r = framePalette[(i * 3) + 0] << 8;
+					palette16[i].g = framePalette[(i * 3) + 1] << 8;
+					palette16[i].b = framePalette[(i * 3) + 2] << 8;
+				}
+				CLBlitter_Send2ScreenNextCopy(palette16, 0, 256);
+			}
+		}
+		_hnmFrameNum = decoder->getCurFrame();
+
 		if (_game->getSpecialTextMode())
 			handleHNMSubtitles();
 		else
 			_game->musicspy();
+
 		CLBlitter_CopyView2Screen(_hnmView);
 		assert(_game->_vm->_screenView->_pitch == 320);
 		_game->_vm->pollEvents();
@@ -1213,9 +1250,12 @@ void EdenGraphics::showMovie(char arg1) {
 			else
 				_game->setMouseNotHeld();
 		}
-	} while (playing && !_videoCanceledFlag);
+
+		g_system->delayMillis(10);
+	} while (!_game->_vm->shouldQuit() && !decoder->endOfVideo() && !_videoCanceledFlag);
+
 	delete _hnmView;
-	_video->deallocMemory();
+	delete decoder;
 }
 
 bool EdenGraphics::getShowBlackBars() {
@@ -1247,17 +1287,17 @@ void EdenGraphics::playHNM(int16 num) {
 	}
 	_showVideoSubtitle = false;
 	_videoCanceledFlag = false;
-	_game->loadHnm(num);
-	_video->reset();
+
 	if (_needToFade) {
 		fadeToBlack(4);
 		clearScreen();
 		_needToFade = false;
 	}
 	if (num == 2012 || num == 98 || num == 171)
-		showMovie(0);
+		showMovie(num, 0);
 	else
-		showMovie(1);
+		showMovie(num, 1);
+
 	_cursKeepPos = Common::Point(-1, -1);
 	if (_game->getSpecialTextMode()) {
 		_game->setMusicFade(3);
diff --git a/engines/cryo/eden_graphics.h b/engines/cryo/eden_graphics.h
index 429e81419e..4fcc1effa3 100644
--- a/engines/cryo/eden_graphics.h
+++ b/engines/cryo/eden_graphics.h
@@ -32,7 +32,7 @@ class HnmPlayer;
 
 class EdenGraphics {
 public:
-	EdenGraphics(EdenGame *game, HnmPlayer *video);
+	EdenGraphics(EdenGame *game);
 
 	// Original name: noclipax
 	void drawSprite(int16 index, int16 x, int16 y, bool withBlack = false, bool onSubtitle = false);
@@ -154,7 +154,6 @@ public:
 
 private:
 	EdenGame *_game;
-	HnmPlayer *_video;
 
 	int16 _glowX;
 	int16 _glowY;
@@ -233,7 +232,7 @@ private:
 
 	////// film.c
 	// Original name: showfilm
-	void showMovie(char arg1);
+	void showMovie(int16 num, char arg1);
 
 	// Original name bullehnm
 	void handleHNMSubtitles();
diff --git a/engines/cryo/module.mk b/engines/cryo/module.mk
index 11227ac5ee..9075459fb0 100644
--- a/engines/cryo/module.mk
+++ b/engines/cryo/module.mk
@@ -8,8 +8,7 @@ MODULE_OBJS = \
 	eden_graphics.o \
 	metaengine.o \
 	resource.o \
-	sound.o \
-	video.o
+	sound.o
 
 # This module can be built as a plugin
 ifeq ($(ENABLE_CRYO), DYNAMIC_PLUGIN)
diff --git a/engines/cryo/resource.cpp b/engines/cryo/resource.cpp
index 3dbfbc4eb1..dc8e945af3 100644
--- a/engines/cryo/resource.cpp
+++ b/engines/cryo/resource.cpp
@@ -27,6 +27,8 @@
 #include "cryo/eden.h"
 #include "cryo/sound.h"
 
+#include "common/substream.h"
+
 namespace Cryo {
 
 #define CRYO_DAT_VER 1	// 32-bit integer
@@ -86,8 +88,6 @@ void EdenGame::openbigfile() {
 		_bigfileHeader->_files[j]._flag = _bigfile.readByte();
 	}
 
-	_vm->_video->resetInternals();
-	_vm->_video->setFile(&_bigfile);
 }
 
 void EdenGame::closebigfile() {
@@ -191,15 +191,13 @@ void EdenGame::loadRoomFile(uint16 num, Room *buffer) {
 	}
 }
 
-// Original name: shnmfl
-void EdenGame::loadHnm(uint16 num) {
-	unsigned int resNum = num - 1 + 485;
+Common::SeekableReadStream *EdenGame::loadSubStream(uint16 resNum) {
 	assert(resNum < _bigfileHeader->_count);
 	PakHeaderItem *file = &_bigfileHeader->_files[resNum];
 	int size = file->_size;
 	int offs = file->_offs;
-	debug("* Loading movie %d (%s) at 0x%X, %d bytes", num, file->_name.c_str(), (uint)offs, size);
-	_vm->_video->_file->seek(offs, SEEK_SET);
+	debug("* Loading file %s at 0x%X, %d bytes", file->_name.c_str(), (uint)offs, size);
+	return new Common::SafeSeekableSubReadStream(&_bigfile, offs, offs + size, DisposeAfterUse::NO);
 }
 
 // Original name: ssndfl
diff --git a/engines/cryo/video.cpp b/engines/cryo/video.cpp
deleted file mode 100644
index 81e3ee171d..0000000000
--- a/engines/cryo/video.cpp
+++ /dev/null
@@ -1,617 +0,0 @@
-/* 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 "cryo/cryo.h"
-#include "cryo/video.h"
-
-namespace Cryo {
-HnmPlayer::HnmPlayer(CryoEngine *vm) : _vm(vm) {
-	_soundStarted = false;
-	_pendingSounds = 0;
-	_timeDrift = 0.0;
-	_nextFrameTime = 0.0;
-	_expectedFrameTime = 0.0;
-	_rate = 0.0;
-	_useSoundSync = false;
-	_useSound = true;
-	_soundChannel = nullptr;
-	_prevRight = _prevLeft = 0;
-	_useAdpcm = false;
-	_customChunkHandler = nullptr;
-	_preserveColor0 = false;
-	_safePalette = false;
-
-	for (int i = 0; i < 256; i++)
-		decompTable[i] = 0;
-}
-
-// Original name: CLHNM_New
-void HnmPlayer::resetInternals() {
-	_frameNum = 0;
-	_file = nullptr;
-	_tmpBuffer[0] = nullptr;
-	_tmpBuffer[1] = nullptr;
-	_finalBuffer = nullptr;
-	_readBuffer = nullptr;
-	for (int i = 0; i < 256; i++) {
-		_palette[i].a = 0;
-		_palette[i].r = 0;
-		_palette[i].g = 0;
-		_palette[i].b = 0;
-	}
-}
-
-// Original name: CLHNM_SetFile
-void HnmPlayer::setFile(Common::File *file) {
-	_file = file;
-}
-
-// Original name: CLHNM_SetupTimer
-void HnmPlayer::setupTimer(float rate) {
-	_rate = 100.0 / rate;
-}
-
-// Original name: CLHNM_ResetInternalTimer
-void HnmPlayer::resetInternalTimer() {
-	_timeDrift = 0.0;
-	_nextFrameTime = _expectedFrameTime = _vm->_timerTicks;
-}
-
-// Original name: CLHNM_Reset
-void HnmPlayer::reset() {
-	_frameNum = 0;
-	_soundStarted = false;
-	_pendingSounds = 0;
-	resetInternalTimer();
-}
-
-// Original name: CLHNM_Init
-void HnmPlayer::init() {
-	_customChunkHandler = nullptr;
-	_preserveColor0 = false;
-	_useSound = true;
-}
-
-// Original name: CLHNM_SetForceZero2Black
-void HnmPlayer::setForceZero2Black(bool forceblack) {
-	_preserveColor0 = forceblack;
-}
-
-// Original name: CLHNM_WaitLoop
-void HnmPlayer::waitLoop() {
-	_expectedFrameTime += _rate;
-	_nextFrameTime = _expectedFrameTime - _timeDrift;
-	if (_useSoundSync && _vm->_timerTicks > 1000.0 + _nextFrameTime)
-		_useSound = false;
-	while (_vm->_timerTicks < _nextFrameTime) {} // waste time
-	_timeDrift = _vm->_timerTicks - _nextFrameTime;
-}
-
-// Original name: CLHNM_WantsSound
-void HnmPlayer::wantsSound(bool sound) {
-	_useSound = sound;
-}
-
-// Original name: CLHNM_SetupSound
-void HnmPlayer::setupSound(unsigned int rate, bool stereo, bool is16bits) {
-	_soundChannel = new CSoundChannel(_vm->_mixer, rate, stereo, is16bits);
-}
-
-// Original name: CLHNM_CloseSound
-void HnmPlayer::closeSound() {
-	if (_soundChannel) {
-		_soundChannel->stop();
-		delete(_soundChannel);
-		_soundChannel = nullptr;
-	}
-}
-
-// Original name: CLHNM_LoadDecompTable
-void HnmPlayer::loadDecompTable(int16 *buffer) {
-	for (int16 i = 0; i < 256; i++) {
-		int16 e = *buffer++;
-		decompTable[i] = FROM_LE_16(e);
-	}
-}
-
-// Original name: CLHNM_DecompADPCM
-void HnmPlayer::decompADPCM(byte *buffer, int16 *output, int size) {
-	int16 l = _prevLeft;
-	int16 r = _prevRight;
-	size &= ~1;
-	while (size--) {
-		*output++ = l += decompTable[*buffer++];
-		*output++ = r += decompTable[*buffer++];
-		if (l > 512 || r > 512)
-			error("decompADPCM - Unexpected values");
-	}
-	_prevLeft = l;
-	_prevRight = r;
-}
-
-// Original name: CLHNM_ReadHeader
-void HnmPlayer::readHeader() {
-	_header._signature = _file->readUint32BE();
-	_file->skip(4);
-	_header._width = _file->readUint16LE();
-	_header._height = _file->readUint16LE();
-	_file->skip(4);
-	_header._numbFrame = _file->readSint32LE();
-	_file->skip(8);
-	_header._bufferSize = _file->readSint32LE();
-	_file->skip(32);
-
-	_header._bufferSize += 4096; //TODO: checkme
-}
-
-// Original name: CLHNM_GetVersion
-int16 HnmPlayer::getVersion() {
-	if (_header._signature == MKTAG('H','N','M','4'))
-		return 4;
-	return -1;
-}
-
-// Original name: CLHNM_AllocMemory
-void HnmPlayer::allocMemory() {
-// TODO: rework this code
-	_tmpBuffer[0] = (byte *)malloc(_header._bufferSize + 2);
-
-	if (!_tmpBuffer[0])
-		return;
-
-	_tmpBuffer[1] = (byte *)malloc(_header._bufferSize + 2);
-
-	if (!_tmpBuffer[1]) {
-		free(_tmpBuffer[0]);
-		_tmpBuffer[0] = nullptr;
-		return;
-	}
-
-	_readBuffer = (byte *)malloc(_header._bufferSize + 2);
-	if (!_readBuffer) {
-		free(_tmpBuffer[0]);
-		_tmpBuffer[0] = nullptr;
-		free(_tmpBuffer[1]);
-		_tmpBuffer[1] = nullptr;
-	}
-}
-
-// Original name: CLHNM_DeallocMemory
-void HnmPlayer::deallocMemory() {
-	free(_tmpBuffer[0]);
-	free(_tmpBuffer[1]);
-	free(_readBuffer);
-
-	_tmpBuffer[0] = nullptr;
-	_tmpBuffer[1] = nullptr;
-	_readBuffer = nullptr;
-}
-
-// Original name: CLHNM_SetFinalBuffer
-void HnmPlayer::setFinalBuffer(byte *buffer) {
-	_finalBuffer = buffer;
-}
-
-// Original name: CLHNM_GetFrameNum
-int HnmPlayer::getFrameNum() {
-	return _frameNum;
-}
-
-// Original name: CLHNM_TryRead
-void HnmPlayer::tryRead(int size) {
-	_file->read(_readBuffer, size);
-}
-
-// Original name: CLHNM_LoadFrame
-bool HnmPlayer::loadFrame() {
-	tryRead(4);
-	int chunk = *(int *)_readBuffer;
-	chunk = FROM_LE_32(chunk);
-	chunk &= 0xFFFFFF;  // upper bit - keyframe mark?
-	if (!chunk)
-		return false;
-
-	if (chunk - 4 > _header._bufferSize)
-		error("loadFrame - Chunk size");
-
-	tryRead(chunk - 4);
-	_dataPtr = _readBuffer;
-	return true;
-}
-
-// Original name CLHNM_DecompLempelZiv
-void HnmPlayer::decompLempelZiv(byte *buffer, byte *output) {
-	byte *inp = buffer;
-	byte *out = output;
-
-	unsigned int queue = 0;
-	int qpos = -1;
-
-	//TODO: fix for BE
-#define GetBit() ( 1 & ( (qpos >= 0) ? (queue >> qpos--) : (queue = *(unsigned int*)((inp += 4) - 4)) >> ((qpos = 30) + 1) ) )
-
-	for (;;) {
-		if (GetBit()) {
-			*out++ = *inp++;
-		} else {
-			int l, o;
-			if (GetBit()) {
-				l = *inp & 7;
-				o = *(uint16 *)inp >> 3;
-				inp += 2;
-				o -= 8192;
-				if (!l)
-					l = *inp++;
-				if (!l)
-					break;
-			} else {
-				l = GetBit() * 2;
-				l += GetBit();
-				o = *(inp++) - 256;
-			}
-			l += 2;
-			while (l--) {
-				*out = *(out + o);
-				out++;
-			}
-		}
-	}
-
-#undef GetBit
-
-	return;
-}
-
-// Original name: CLHNM_Desentrelace320
-void HnmPlayer::desentrelace320(byte *frame_buffer, byte *final_buffer, uint16 height) {
-	unsigned int *input = (unsigned int *)frame_buffer;
-	unsigned int *line0 = (unsigned int *)final_buffer;
-	unsigned int *line1 = (unsigned int *)(final_buffer + 320);
-	int count = (height) / 2;
-	while (count--) {
-		int16 i;
-		for (i = 0; i < 320 / 4; i++) {
-			unsigned int p0 = *input++;
-			unsigned int p4 = *input++;
-#if 0
-			*line0++ = ((p4 & 0xFF00) >> 8) | ((p4 & 0xFF000000) >> 16) | ((p0 & 0xFF00) << 8) | (p0 & 0xFF000000);
-			//			*line0++ = (p0 & 0xFF000000) | ((p0 & 0xFF00) << 8) | ((p4 & 0xFF000000) >> 16) | ((p4 & 0xFF00) >> 8);
-			*line1++ = ((p0 & 0xFF0000) << 8) | ((p0 & 0xFF) << 16) | ((p4 & 0xFF0000) >> 8) | (p4 & 0xFF);
-#else
-			*line0++ = (p0 & 0xFF) | ((p0 & 0xFF0000) >> 8) | ((p4 & 0xFF) << 16) | ((p4 & 0xFF0000) << 8);
-			*line1++ = ((p0 & 0xFF00) >> 8) | ((p0 & 0xFF000000) >> 16) | ((p4 & 0xFF00) << 8) | (p4 & 0xFF000000);
-#endif
-		}
-		line0 += 320 / 4;
-		line1 += 320 / 4;
-	}
-}
-
-// Original name: CLHNM_Desentrelace
-void HnmPlayer::desentrelace() {
-	switch (_header._width) {
-	case 320:
-		desentrelace320(_newFrameBuffer, _finalBuffer, _header._height);
-		break;
-		//	case 480:
-		//		CLHNM_Desentrelace480(_newFrameBuffer, finalBuffer, _header._height);
-		//		break;
-	default:
-		error("desentrelace - Unexpected width");
-	}
-}
-
-// Original name: CLHNM_DecompUBA
-void HnmPlayer::decompUBA(byte *output, byte *curr_buffer, byte *prev_buffer, byte *input, int width, char flags) {
-	 //	return;
-	byte *out_start = output;
-	byte count;
-	unsigned int code;
-	uint16 offs;
-	byte mode;
-	byte swap;
-
-	if ((flags & 1) == 0) {
-		//HNM4 classic
-		int twolinesabove = -(width * 2);
-		for (;;) {
-			code = READ_LE_UINT32(input) & 0xFFFFFF; //input++;
-			count = code & 0x1F;
-			if (count) {
-				input += 3;
-				offs = code >> 9;
-				//
-				mode = (code >> 5) & 0xF;
-				swap = mode >> 3;
-				byte *ref = ((mode & 1) ? prev_buffer : curr_buffer) + (output - out_start) + (offs * 2) - 32768;
-				int shft1, shft2;
-				if (mode & 2) {
-					// ref += twolinesabove;
-					shft1 = twolinesabove + 1;
-					shft2 = 0;
-					//swap ^= 1;
-				} else {
-					shft1 = 0;
-					shft2 = 1;
-				}
-				while (count--) {
-					byte b0 = ref[shft1];
-					byte b1 = ref[shft2];
-					output[swap] = b0;
-					output[swap ^ 1] = b1;
-					output += 2;
-					ref += (mode & 4) ? -2 : 2;
-				}
-			} else {
-				input++;
-				mode = code & 0xFF; // bits 0..4 are zero
-				switch (mode) {
-				case 0:
-					*(output++) = *(input++);
-					*(output++) = *(input++);
-					break;
-				case 0x20:
-					output += 2 * *(input++);
-					break;
-				case 0x40:
-					output += 2 * (code >> 8);
-					input += 2;
-					break;
-				case 0x60: {
-					count = *(input++);
-					byte color = *(input++);
-					while (count--) {
-						*(output++) = color;
-						*(output++) = color;
-					}
-					break;
-					}
-				default:
-					return;
-				}
-			}
-		}
-	} else {
-		assert(0);
-		//HNM4 hires
-		for (;;) {
-			code = READ_LE_UINT32(input) & 0xFFFFFF;
-			input++;
-			count = code & 0x3F;
-			if (count) {
-				mode = (code >> 5) & 0xF;
-				offs = code >> 9;
-				//
-			} else {
-				mode = code & 0xFF; // bits 0..5 are zero
-				switch (mode) {
-				case 0x00:
-					output += *input++;
-					break;
-				case 0x40:
-					*output++ = *input++;
-					*(output++ + width) = *input++;
-					break;
-				case 0x80:
-					output += width;
-					break;
-				default:
-					return;
-				}
-			}
-		}
-	}
-}
-
-// Original name: CLHNM_NextElement
-bool HnmPlayer::nextElement() {
-	if (_frameNum == 0) {
-		resetInternalTimer();
-		_prevLeft = _prevRight = 0;
-	}
-	if (_frameNum == _header._numbFrame)
-		return false;
-
-	if (!loadFrame())
-		return false;
-
-	for (;;) {
-		int sz = READ_LE_UINT32(_dataPtr) & 0xFFFFFF;
-		_dataPtr += 4;
-		int16 id = READ_LE_UINT16(_dataPtr);
-		_dataPtr += 2;
-		char h6 = *_dataPtr;
-		_dataPtr += 1;
-		char h7 = *_dataPtr;
-		_dataPtr += 1;
-		switch (id) {
-		case MKTAG16('L', 'P'):
-			changePalette();
-			_dataPtr += sz - 8;
-			break;
-		case MKTAG16('Z', 'I'):
-			_frameNum++;
-			selectBuffers();
-			decompLempelZiv(_dataPtr + 4, _newFrameBuffer);
-#if 0
-			switch (_header._width) {
-			case 320:
-				CLBlitter_RawCopy320ASM(_newFrameBuffer, _oldFrameBuffer, _header._height);
-				break;
-			case 480:
-				CLBlitter_RawCopy480ASM(_newFrameBuffer, _oldFrameBuffer, _header._height);
-				break;
-			case 640:
-				CLBlitter_RawCopy640ASM(_newFrameBuffer, _oldFrameBuffer, _header._height);
-				break;
-			default: 
-				memcpy(_oldFrameBuffer, _newFrameBuffer, _header._width * _header._height);
-			}
-#else
-			memcpy(_oldFrameBuffer, _newFrameBuffer, _header._bufferSize);  //TODO strange buffer size here
-#endif
-			if (!(h6 & 1))
-				desentrelace();
-			else {
-				//				if(_header._width == 640)
-				//					CLBlitter_RawCopy640(_newFrameBuffer, finalBuffer, _header._height);
-				//				else
-				memcpy(_finalBuffer, _newFrameBuffer, _header._height);   //TODO: wrong size?
-			}
-
-			if (!_soundStarted) {
-				_soundChannel->play();
-				_soundStarted = true;
-			}
-
-			return true;
-		case MKTAG16('U', 'I'):
-			_frameNum++;
-			selectBuffers();
-			decompUBA(_newFrameBuffer, _newFrameBuffer, _oldFrameBuffer, _dataPtr, _header._width, h6);
-			if (!(h6 & 1))
-				desentrelace();
-			else {
-				//				if(_header._width == 640)
-				//					CLBlitter_RawCopy640(_newFrameBuffer, _finalBuffer, _header._height);
-				//				else
-				memcpy(_finalBuffer, _newFrameBuffer, _header._width * _header._height);
-			}
-			return true;
-
-		case MKTAG16('d', 's'):
-		case MKTAG16('D', 'S'):
-			if (_useSound) {
-				if (!h6) {
-					int sound_size = sz - 8;
-					if (!_useAdpcm) {
-						_soundChannel->queueBuffer(_dataPtr, sound_size - 2, false, _soundStarted);
-					} else {
-#if 0
-						// Not used in Lost Eden
-						int16 *sound_buffer = (int16 *)_soundGroup->getNextBuffer();
-						if (!_pendingSounds) {
-							const int kDecompTableSize = 256 * sizeof(int16);
-							loadDecompTable((int16 *)_dataPtr);
-							decompADPCM(_dataPtr + kDecompTableSize, sound_buffer, sound_size - kDecompTableSize);
-							_soundGroup->assignDatas(sound_buffer, (sound_size - kDecompTableSize) * 2, false);
-						} else {
-							decompADPCM(_dataPtr, sound_buffer, sound_size);
-							_soundGroup->assignDatas(sound_buffer, sound_size * 2, false);
-						}
-						_pendingSounds++;
-						if (_soundStarted)
-							_soundGroup->playNextSample(_soundChannel);
-#endif
-					}
-				} else
-					error("nextElement - unexpected flag");
-			}
-			_dataPtr += sz - 8;
-			break;
-		default:
-			if (_customChunkHandler)
-				_customChunkHandler(_dataPtr, sz - 8, id, h6, h7);
-			_dataPtr += sz - 8;
-		}
-	}
-	return true;
-}
-
-// Original name: CLHNM_GetSoundChannel
-CSoundChannel *HnmPlayer::getSoundChannel() {
-	return _soundChannel;
-}
-
-// Original name: CLHNM_ChangePalette
-void HnmPlayer::changePalette() {
-	CLPalette_GetLastPalette(_palette);
-	byte *pal = _dataPtr;
-	if (*(uint16 *)pal == 0xFFFF)
-		return;
-
-	int16 mincolor = 255;
-	int16 maxcolor = 0;
-	do {
-		uint16 fst = *pal++;
-		uint16 cnt = *pal++;
-		if (cnt == 0)
-			cnt = 256;
-		debug("hnm: setting palette, fst = %d, cnt = %d, last = %d", fst, cnt, fst + cnt - 1);
-		assert(fst + cnt <= 256);
-		if (mincolor > fst)
-			mincolor = fst;
-		if (maxcolor < fst + cnt)
-			maxcolor = fst + cnt;
-		color_t *color = _palette + fst;
-		if (_safePalette) {
-			while (cnt--) {
-				byte r = *pal++;
-				byte g = *pal++;
-				byte b = *pal++;
-				int16 rr = r << 10;
-				int16 gg = g << 10;
-				int16 bb = b << 10;
-				if (color->r != rr || color->g != gg || color->b != bb)
-					CLBlitter_OneBlackFlash();
-				color->r = rr;
-				color->g = gg;
-				color->b = bb;
-				color++;
-			}
-		} else {
-			while (cnt--) {
-				byte r = *pal++;
-				byte g = *pal++;
-				byte b = *pal++;
-				color->r = r << 10;
-				color->g = g << 10;
-				color->b = b << 10;
-				color++;
-			}
-		}
-
-	} while (*(uint16 *)pal != 0xFFFF);
-#if 0
-	if (preserve_color0) {
-		_palette[0].r = 0;
-		_palette[0].g = 0;
-		_palette[0].b = 0;
-	}
-#endif
-	//	CLBlitter_Send2ScreenNextCopy(_palette, mincolor, maxcolor - mincolor);
-	CLBlitter_Send2ScreenNextCopy(_palette, 0, 256);
-}
-
-// Original name: CLHNM_SelectBuffers
-void HnmPlayer::selectBuffers() {
-	if (_frameNum % 2) {
-		_newFrameBuffer = _tmpBuffer[1];
-		_oldFrameBuffer = _tmpBuffer[0];
-	} else {
-		_newFrameBuffer = _tmpBuffer[0];
-		_oldFrameBuffer = _tmpBuffer[1];
-	}
-}
-
-}   // namespace Cryo
-
diff --git a/engines/cryo/video.h b/engines/cryo/video.h
deleted file mode 100644
index 83eddfb9b1..0000000000
--- a/engines/cryo/video.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/* 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 CRYO_VIDEO_H
-#define CRYO_VIDEO_H
-
-#include "cryo/sound.h"
-
-namespace Cryo {
-
-class CryoEngine;
-
-class HnmPlayer {
-public:
-	Common::File *_file;
-	HNMHeader     _header;
-
-private:
-	CryoEngine *_vm;
-
-	void resetInternalTimer();
-	void wantsSound(bool sound);
-	void decompADPCM(byte *buffer, int16 *output, int size);
-	void loadDecompTable(int16 *buffer);
-	bool loadFrame();
-	void tryRead(int size);
-	void changePalette();
-	void selectBuffers();
-	void decompLempelZiv(byte *buffer, byte *output);
-	void desentrelace320(byte *frame_buffer, byte *final_buffer, uint16 height);
-	void desentrelace();
-	void decompUBA(byte *output, byte *curr_buffer, byte *prev_buffer, byte *input, int width, char flags);
-	void setupSoundADPCM(int16 numSounds, int16 length, int16 sampleSize, float rate, int16 mode);
-	void init();
-
-	bool _soundStarted;
-	int16 _pendingSounds;
-	float _timeDrift;
-	float _nextFrameTime;
-	float _expectedFrameTime;
-	float _rate;
-	bool _useSoundSync;
-	bool _useSound;
-	int16 _prevRight;
-	int16 _prevLeft;
-	bool _useAdpcm;
-	bool _preserveColor0;
-	int16 decompTable[256];
-	bool _safePalette;
-	int     _frameNum;
-	byte   *_tmpBuffer[2];
-	byte   *_finalBuffer;
-	byte   *_newFrameBuffer;
-	byte   *_oldFrameBuffer;
-	byte   *_readBuffer;
-	byte   *_dataPtr;
-	color_t _palette[256];
-	int     _totalRead;
-
-	void (*_customChunkHandler)(byte *buffer, int size, int16 id, char h6, char h7);
-
-	CSoundChannel *_soundChannel;
-
-public:
-	HnmPlayer(CryoEngine *vm);
-
-	void allocMemory();
-	void closeSound();
-	void deallocMemory();
-	int getFrameNum();
-	CSoundChannel *getSoundChannel();
-	int16 getVersion();
-	bool nextElement();
-	void reset();
-	void readHeader();
-	void resetInternals();
-	void setFile(Common::File *file);
-	void setFinalBuffer(byte *buffer);
-	void setForceZero2Black(bool forceblack);
-	void setupSound(unsigned int rate, bool stereo, bool is16bits);
-	void setupTimer(float rate);
-	void waitLoop();
-};
-
-} // End of namespace Cryo
-
-#endif
diff --git a/video/hnm_decoder.h b/video/hnm_decoder.h
index 5752f803de..fa5a43e2af 100644
--- a/video/hnm_decoder.h
+++ b/video/hnm_decoder.h
@@ -39,6 +39,7 @@ namespace Video {
  * Decoder for HNM videos.
  *
  * Video decoder used in engines:
+ *  - cryo
  *  - cryomni3d
  */
 class HNMDecoder : public VideoDecoder {


Commit: f1e90ada2f10fec8bdb74d74fc8e8560bfb4d9c3
    https://github.com/scummvm/scummvm/commit/f1e90ada2f10fec8bdb74d74fc8e8560bfb4d9c3
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2021-04-17T21:48:46+03:00

Commit Message:
VIDEO: Optimize HNM4 decoding slightly

Changed paths:
    video/hnm_decoder.cpp


diff --git a/video/hnm_decoder.cpp b/video/hnm_decoder.cpp
index e9465fe0a9..7fd232a21f 100644
--- a/video/hnm_decoder.cpp
+++ b/video/hnm_decoder.cpp
@@ -304,9 +304,8 @@ void HNMDecoder::HNM4VideoTrack::decodeInterframe(Common::SeekableReadStream *st
 				// Fill (next byte of input) * 2 of output with (next byte of input)
 				c = stream->readByte() * 2;
 				fill = stream->readByte();
-				while (c--) {
-					_frameBufferC[currentPos++] = fill;
-				}
+				memset(&_frameBufferC[currentPos], fill, c);
+				currentPos += c;
 				size -= 2;
 				break;
 			default:
@@ -485,27 +484,26 @@ void HNMDecoder::HNM4VideoTrack::postprocess(uint16 flags) {
 	if ((flags & 1) == 1) {
 		memcpy(_frameBufferF, _frameBufferC, width * height);
 	} else if ((width % 4) == 0) {
-		byte *input = _frameBufferC;
-		byte *line0 = _frameBufferF;
-		byte *line1 = _frameBufferF + width;
+		uint32 *input = (uint32 *)_frameBufferC;
+		uint32 *line0 = (uint32 *)_frameBufferF;
+		uint32 *line1 = (uint32 *)(_frameBufferF + width);
 		int count = (height) / 2;
 		while (count--) {
-			int16 i;
+			int i;
 			for (i = 0; i < width / 4; i++) {
-				byte p0 = *input++, p1 = *input++, p2 = *input++, p3 = *input++;
-				byte p4 = *input++, p5 = *input++, p6 = *input++, p7 = *input++;
-
-				*line0++ = p0;
-				*line0++ = p2;
-				*line0++ = p4;
-				*line0++ = p6;
-				*line1++ = p1;
-				*line1++ = p3;
-				*line1++ = p5;
-				*line1++ = p7;
+				uint32 p0 = *input++;
+				uint32 p4 = *input++;
+
+#ifndef SCUMM_LITTLE_ENDIAN
+				*line0++ = ((p4 & 0xFF00) >> 8) | ((p4 & 0xFF000000) >> 16) | ((p0 & 0xFF00) << 8) | (p0 & 0xFF000000);
+				*line1++ = ((p0 & 0xFF0000) << 8) | ((p0 & 0xFF) << 16) | ((p4 & 0xFF0000) >> 8) | (p4 & 0xFF);
+#else
+				*line0++ = (p0 & 0xFF) | ((p0 & 0xFF0000) >> 8) | ((p4 & 0xFF) << 16) | ((p4 & 0xFF0000) << 8);
+				*line1++ = ((p0 & 0xFF00) >> 8) | ((p0 & 0xFF000000) >> 16) | ((p4 & 0xFF00) << 8) | (p4 & 0xFF000000);
+#endif
 			}
-			line0 += width;
-			line1 += width;
+			line0 += width / 4;
+			line1 += width / 4;
 		}
 	} else {
 		error("HNMDecoder::HNM4VideoTrack::postprocess(%x): Unexpected width: %d", flags, width);


Commit: 0953a690f4d7dd24aaedd46cc1c6ea0ea6adb9a7
    https://github.com/scummvm/scummvm/commit/0953a690f4d7dd24aaedd46cc1c6ea0ea6adb9a7
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-04-17T21:48:46+03:00

Commit Message:
VIDEO: Fix HNM decoding

Bytes are both read before written

Changed paths:
    video/hnm_decoder.cpp


diff --git a/video/hnm_decoder.cpp b/video/hnm_decoder.cpp
index 7fd232a21f..a0fef837e6 100644
--- a/video/hnm_decoder.cpp
+++ b/video/hnm_decoder.cpp
@@ -349,10 +349,15 @@ void HNMDecoder::HNM4VideoTrack::decodeInterframe(Common::SeekableReadStream *st
 			if (swap)
 				SWAP(shft1, shft2);
 
+			int src_inc = backward ? -2 : 2;
+
 			while (count--) {
-				_frameBufferC[currentPos++] = ptr[offset + shft1];
-				_frameBufferC[currentPos++] = ptr[offset + shft2];
-				offset += backward ? -2 : 2;
+				byte b0 = ptr[offset + shft1];
+				byte b1 = ptr[offset + shft2];
+				_frameBufferC[currentPos++] = b0;
+				_frameBufferC[currentPos++] = b1;
+
+				offset += src_inc;
 			}
 		}
 	}


Commit: bf7ddf6a70126c8e779f9ae8bcebfe541450c62f
    https://github.com/scummvm/scummvm/commit/bf7ddf6a70126c8e779f9ae8bcebfe541450c62f
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-04-17T21:48:47+03:00

Commit Message:
VIDEO: HNM Postprocessing simplification

Don't pass flags to various decoding blocks thay don't need it.
Unifiy frame handling in a unique procedure which handles deinterlacing.
Don't memcpy with HNM4A frames, point the surface at framebuffer

Changed paths:
    video/hnm_decoder.cpp
    video/hnm_decoder.h


diff --git a/video/hnm_decoder.cpp b/video/hnm_decoder.cpp
index a0fef837e6..9c1fc55678 100644
--- a/video/hnm_decoder.cpp
+++ b/video/hnm_decoder.cpp
@@ -133,13 +133,15 @@ void HNMDecoder::readNextPacket() {
 			_videoTrack->decodePalette(_stream, chunkSize - 8);
 		} else if (chunkType == MKTAG16('I', 'Z')) {
 			_stream->skip(4);
-			_videoTrack->decodeIntraframe(_stream, chunkSize - 8 - 4, flags);
+			_videoTrack->decodeIntraframe(_stream, chunkSize - 8 - 4);
+			_videoTrack->presentFrame(flags);
 		} else if (chunkType == MKTAG16('I', 'U')) {
 			if ((flags & 1) == 1) {
-				_videoTrack->decodeInterframeA(_stream, chunkSize - 8, flags);
+				_videoTrack->decodeInterframeA(_stream, chunkSize - 8);
 			} else {
-				_videoTrack->decodeInterframe(_stream, chunkSize - 8, flags);
+				_videoTrack->decodeInterframe(_stream, chunkSize - 8);
 			}
+			_videoTrack->presentFrame(flags);
 		} else if (chunkType == MKTAG16('S', 'D')) {
 			if (_audioTrack) {
 				Audio::Timestamp duration = _audioTrack->decodeSound(_stream, chunkSize - 8);
@@ -181,8 +183,9 @@ HNMDecoder::HNM4VideoTrack::HNM4VideoTrack(uint32 width, uint32 height, uint32 f
 	_frameBufferP = new byte[frameSize];
 	memset(_frameBufferP, 0, frameSize);
 
+	// We will use _frameBufferF/C/P as the surface pixels, just init there with nullptr to avoid unintended usage of surface
 	const Graphics::PixelFormat &f = Graphics::PixelFormat::createFormatCLUT8();
-	_surface.init(width, height, width * f.bytesPerPixel, _frameBufferF, f);
+	_surface.init(width, height, width * f.bytesPerPixel, nullptr, f);
 }
 
 HNMDecoder::HNM4VideoTrack::~HNM4VideoTrack() {
@@ -247,7 +250,7 @@ void HNMDecoder::HNM4VideoTrack::decodePalette(Common::SeekableReadStream *strea
 	}
 }
 
-void HNMDecoder::HNM4VideoTrack::decodeInterframe(Common::SeekableReadStream *stream, uint32 size, uint16 flags) {
+void HNMDecoder::HNM4VideoTrack::decodeInterframe(Common::SeekableReadStream *stream, uint32 size) {
 	SWAP(_frameBufferC, _frameBufferP);
 
 	uint16 width = _surface.w;
@@ -361,19 +364,12 @@ void HNMDecoder::HNM4VideoTrack::decodeInterframe(Common::SeekableReadStream *st
 			}
 		}
 	}
-	postprocess(flags);
-
-	_curFrame++;
-	_nextFrameStartTime += _nextFrameDelay != uint32(-1) ? _nextFrameDelay : _regularFrameDelay;
-	_nextFrameDelay = _nextNextFrameDelay;
-	_nextNextFrameDelay = uint32(-1);
-
 	if (size > 0) {
 		stream->skip(size);
 	}
 }
 
-void HNMDecoder::HNM4VideoTrack::decodeInterframeA(Common::SeekableReadStream *stream, uint32 size, uint16 flags) {
+void HNMDecoder::HNM4VideoTrack::decodeInterframeA(Common::SeekableReadStream *stream, uint32 size) {
 	SWAP(_frameBufferC, _frameBufferP);
 
 	uint16 width = _surface.w;
@@ -459,36 +455,26 @@ void HNMDecoder::HNM4VideoTrack::decodeInterframeA(Common::SeekableReadStream *s
 			}
 		}
 	}
-	postprocess(flags);
-
-	_curFrame++;
-	_nextFrameStartTime += _nextFrameDelay != uint32(-1) ? _nextFrameDelay : _regularFrameDelay;
-	_nextFrameDelay = _nextNextFrameDelay;
-	_nextNextFrameDelay = uint32(-1);
 
 	if (size > 0) {
 		stream->skip(size);
 	}
 }
 
-void HNMDecoder::HNM4VideoTrack::decodeIntraframe(Common::SeekableReadStream *stream, uint32 size, uint16 flags) {
+void HNMDecoder::HNM4VideoTrack::decodeIntraframe(Common::SeekableReadStream *stream, uint32 size) {
 	Image::HLZDecoder::decodeFrameInPlace(*stream, size, _frameBufferC);
 	memcpy(_frameBufferP, _frameBufferC, (uint)_surface.w * (uint)_surface.h);
-	postprocess(flags);
-
-	_curFrame++;
-	_nextFrameStartTime += _nextFrameDelay != uint32(-1) ? _nextFrameDelay : _regularFrameDelay;
-	_nextFrameDelay = _nextNextFrameDelay;
-	_nextNextFrameDelay = uint32(-1);
 }
 
-void HNMDecoder::HNM4VideoTrack::postprocess(uint16 flags) {
+void HNMDecoder::HNM4VideoTrack::presentFrame(uint16 flags) {
 	int width = _surface.w;
 	int height = _surface.h;
 
 	if ((flags & 1) == 1) {
-		memcpy(_frameBufferF, _frameBufferC, width * height);
+		// High resolution HNM4A: no deinterlacing, use current image directly
+		_surface.setPixels(_frameBufferC);
 	} else if ((width % 4) == 0) {
+		// HNM4: deinterlacing must not alter the framebuffer as it will get reused as previous source for next frame
 		uint32 *input = (uint32 *)_frameBufferC;
 		uint32 *line0 = (uint32 *)_frameBufferF;
 		uint32 *line1 = (uint32 *)(_frameBufferF + width);
@@ -510,9 +496,16 @@ void HNMDecoder::HNM4VideoTrack::postprocess(uint16 flags) {
 			line0 += width / 4;
 			line1 += width / 4;
 		}
+		_surface.setPixels(_frameBufferF);
 	} else {
 		error("HNMDecoder::HNM4VideoTrack::postprocess(%x): Unexpected width: %d", flags, width);
 	}
+
+	// Frame done
+	_curFrame++;
+	_nextFrameStartTime += _nextFrameDelay != uint32(-1) ? _nextFrameDelay : _regularFrameDelay;
+	_nextFrameDelay = _nextNextFrameDelay;
+	_nextNextFrameDelay = uint32(-1);
 }
 
 HNMDecoder::DPCMAudioTrack::DPCMAudioTrack(uint16 channels, uint16 bits, uint sampleRate,
diff --git a/video/hnm_decoder.h b/video/hnm_decoder.h
index fa5a43e2af..02687f3fc1 100644
--- a/video/hnm_decoder.h
+++ b/video/hnm_decoder.h
@@ -73,10 +73,10 @@ private:
 
 		/** Decode a video chunk. */
 		void decodePalette(Common::SeekableReadStream *stream, uint32 size);
-		void decodeInterframe(Common::SeekableReadStream *stream, uint32 size, uint16 flags);
-		void decodeInterframeA(Common::SeekableReadStream *stream, uint32 size, uint16 flags);
-		void decodeIntraframe(Common::SeekableReadStream *stream, uint32 size, uint16 flags);
-		void postprocess(uint16 flags);
+		void decodeInterframe(Common::SeekableReadStream *stream, uint32 size);
+		void decodeInterframeA(Common::SeekableReadStream *stream, uint32 size);
+		void decodeIntraframe(Common::SeekableReadStream *stream, uint32 size);
+		void presentFrame(uint16 flags);
 
 		void restart() { _nextFrameDelay = uint32(-1); _nextNextFrameDelay = uint32(-1); }
 		void setFrameDelay(uint32 frameDelay);


Commit: 9a31a8926ccc36853a13150ec3469f7325da9512
    https://github.com/scummvm/scummvm/commit/9a31a8926ccc36853a13150ec3469f7325da9512
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-04-17T21:49:33+03:00

Commit Message:
VIDEO: HNM channels attribute is not channels but some kind of format

Sound is mono when this attribute is at 2

Changed paths:
    video/hnm_decoder.cpp
    video/hnm_decoder.h


diff --git a/video/hnm_decoder.cpp b/video/hnm_decoder.cpp
index 9c1fc55678..0c9394c049 100644
--- a/video/hnm_decoder.cpp
+++ b/video/hnm_decoder.cpp
@@ -69,7 +69,7 @@ bool HNMDecoder::loadStream(Common::SeekableReadStream *stream) {
 	//uint32 tabOffset = stream->readUint32LE();
 	stream->skip(4);
 	uint16 soundBits = stream->readUint16LE();
-	uint16 soundChannels = stream->readUint16LE();
+	uint16 soundFormat = stream->readUint16LE();
 	uint32 frameSize = stream->readUint32LE();
 
 	byte unknownStr[16];
@@ -84,14 +84,14 @@ bool HNMDecoder::loadStream(Common::SeekableReadStream *stream) {
 
 	_videoTrack = new HNM4VideoTrack(width, height, frameSize, frameCount, _regularFrameDelay,
 	                                 _initialPalette);
-	if (soundBits != 0 && soundChannels != 0) {
+	addTrack(_videoTrack);
+	if (soundFormat == 2 && soundBits != 0) {
 		// HNM4 is 22050Hz
-		_audioTrack = new DPCMAudioTrack(soundChannels, soundBits, 22050, getSoundType());
+		_audioTrack = new DPCMAudioTrack(soundFormat, soundBits, 22050, getSoundType());
+		addTrack(_audioTrack);
 	} else {
 		_audioTrack = nullptr;
 	}
-	addTrack(_videoTrack);
-	addTrack(_audioTrack);
 
 	_stream = stream;
 
@@ -147,7 +147,7 @@ void HNMDecoder::readNextPacket() {
 				Audio::Timestamp duration = _audioTrack->decodeSound(_stream, chunkSize - 8);
 				_videoTrack->setFrameDelay(duration.msecs());
 			} else {
-				error("Shouldn't have audio data");
+				warning("Got audio data without an audio track");
 			}
 		} else {
 			error("Got %d chunk: size %d", chunkType, chunkSize);
@@ -508,15 +508,16 @@ void HNMDecoder::HNM4VideoTrack::presentFrame(uint16 flags) {
 	_nextNextFrameDelay = uint32(-1);
 }
 
-HNMDecoder::DPCMAudioTrack::DPCMAudioTrack(uint16 channels, uint16 bits, uint sampleRate,
-		Audio::Mixer::SoundType soundType) : AudioTrack(soundType), _audioStream(nullptr),
+HNMDecoder::DPCMAudioTrack::DPCMAudioTrack(uint16 format, uint16 bits, uint sampleRate,
+        Audio::Mixer::SoundType soundType) : AudioTrack(soundType), _audioStream(nullptr),
 	_gotLUT(false), _lastSample(0) {
 	if (bits != 16) {
 		error("Unsupported audio bits");
 	}
-	if (channels != 2) {
-		warning("Unsupported %d audio channels", channels);
+	if (format != 2) {
+		warning("Unsupported %d audio format", format);
 	}
+	// Format 2 is Mono 16-bits DPCM
 	_audioStream = Audio::makeQueuingAudioStream(sampleRate, false);
 }
 
@@ -555,7 +556,6 @@ Audio::Timestamp HNMDecoder::DPCMAudioTrack::decodeSound(Common::SeekableReadStr
 #ifdef SCUMM_LITTLE_ENDIAN
 		flags |= Audio::FLAG_LITTLE_ENDIAN;
 #endif
-		// channels is 2 but we are MONO!
 		_audioStream->queueBuffer((byte *)out, size * sizeof(*out), DisposeAfterUse::YES, flags);
 	}
 	return Audio::Timestamp(0, size, 22050);
diff --git a/video/hnm_decoder.h b/video/hnm_decoder.h
index 02687f3fc1..3e03ca0643 100644
--- a/video/hnm_decoder.h
+++ b/video/hnm_decoder.h
@@ -102,7 +102,7 @@ private:
 
 	class DPCMAudioTrack : public AudioTrack {
 	public:
-		DPCMAudioTrack(uint16 channels, uint16 bits, uint sampleRate,
+		DPCMAudioTrack(uint16 format, uint16 bits, uint sampleRate,
 		               Audio::Mixer::SoundType soundType);
 		~DPCMAudioTrack() override;
 




More information about the Scummvm-git-logs mailing list