[Scummvm-git-logs] scummvm master -> bb3fb4a963fd2e3abe6ed7c3eea60523ebd35093

dreammaster dreammaster at scummvm.org
Fri Aug 25 13:22:26 CEST 2017


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

Summary:
085ec30b49 IMAGE: Add support for Indeo4 transparency plane
7dd2c0342d IMAGE: Remove unnecessary temporary surface in Indeo4/5
d39a9272bf IMAGE: Remove unnecessary extra heap allocation of Indeo surface
4a39f85c1b IMAGE: Implement handling of key color in Indeo transparency
2b46eda5b6 IMAGE: Allow Indeo4 transparency decoding in scalable videos
bb3fb4a963 Merge pull request #1000 from csnover/indeo4-transparency


Commit: 085ec30b49fedb032bd9b09cb5dc1729ffc54c0f
    https://github.com/scummvm/scummvm/commit/085ec30b49fedb032bd9b09cb5dc1729ffc54c0f
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-08-24T20:34:16-05:00

Commit Message:
IMAGE: Add support for Indeo4 transparency plane

This is used by TITANIC for most of the furniture in the SGT
stateroom and Titania's parts.

Changed paths:
    image/codecs/indeo/indeo.cpp
    image/codecs/indeo/indeo.h
    image/codecs/indeo4.cpp
    image/codecs/indeo4.h


diff --git a/image/codecs/indeo/indeo.cpp b/image/codecs/indeo/indeo.cpp
index f420069..6b6e355 100644
--- a/image/codecs/indeo/indeo.cpp
+++ b/image/codecs/indeo/indeo.cpp
@@ -491,6 +491,8 @@ IndeoDecoderBase::~IndeoDecoderBase() {
 	IVIPlaneDesc::freeBuffers(_ctx._planes);
 	if (_ctx._mbVlc._custTab._table)
 		_ctx._mbVlc._custTab.freeVlc();
+	if (_ctx._transVlc._custTab._table)
+		_ctx._transVlc._custTab.freeVlc();
 
 	delete _ctx._pFrame;
 }
@@ -575,11 +577,23 @@ int IndeoDecoderBase::decodeIndeoFrame() {
 	outputPlane(&_ctx._planes[2], frame->_data[1], frame->_linesize[1]);
 	outputPlane(&_ctx._planes[1], frame->_data[2], frame->_linesize[2]);
 
+	// Merge the planes into the final surface
+	Graphics::Surface s = _surface->getSubArea(Common::Rect(0, 0, _surface->w, _surface->h));
+	YUVToRGBMan.convert410(&s, Graphics::YUVToRGBManager::kScaleITU,
+		frame->_data[0], frame->_data[1], frame->_data[2], frame->_width, frame->_height,
+		frame->_width, frame->_width);
+
+	if (_ctx._hasTransp)
+		decodeTransparency();
+
 	// If the bidirectional mode is enabled, next I and the following P
 	// frame will be sent together. Unfortunately the approach below seems
 	// to be the only way to handle the B-frames mode.
 	// That's exactly the same Intel decoders do.
 	if (_ctx._isIndeo4 && _ctx._frameType == IVI4_FRAMETYPE_INTRA) {
+		// TODO: It appears from the reference decoder that this should be
+		// aligning GetBits to a 32-bit boundary before reading again?
+
 		int left;
 
 		// skip version string
@@ -595,19 +609,9 @@ int IndeoDecoderBase::decodeIndeoFrame() {
 		}
 	}
 
-	// Merge the planes into the final surface
-	Graphics::Surface s = _surface->getSubArea(Common::Rect(0, 0, _surface->w, _surface->h));
-	YUVToRGBMan.convert410(&s, Graphics::YUVToRGBManager::kScaleITU,
-		frame->_data[0], frame->_data[1], frame->_data[2], frame->_width, frame->_height,
-		frame->_width, frame->_width);
-
 	// Free the now un-needed frame data
 	frame->freeFrame();
 
-	// If there's any transparency data, decode it
-	if (_ctx._hasTransp)
-		decodeTransparency();
-
 	return 0;
 }
 
diff --git a/image/codecs/indeo/indeo.h b/image/codecs/indeo/indeo.h
index dcb7330..962d068 100644
--- a/image/codecs/indeo/indeo.h
+++ b/image/codecs/indeo/indeo.h
@@ -398,6 +398,7 @@ public:
 
 	IVIHuffTab		_mbVlc;			///< current macroblock table descriptor
 	IVIHuffTab		_blkVlc;		///< current block table descriptor
+	IVIHuffTab		_transVlc;		///< current transparency table descriptor
 
 	uint8			_rvmapSel;
 	bool			_inImf;
@@ -566,7 +567,7 @@ protected:
 	/**
 	 * Decodes optional transparency data within Indeo frames
 	 */
-	virtual void decodeTransparency() {}
+	virtual int decodeTransparency() { return -1; }
 
 	/**
 	 * Decodes the Indeo frame from the bit reader already
diff --git a/image/codecs/indeo4.cpp b/image/codecs/indeo4.cpp
index ead1d3a..40f86f8 100644
--- a/image/codecs/indeo4.cpp
+++ b/image/codecs/indeo4.cpp
@@ -26,7 +26,9 @@
  * written, produced, and directed by Alan Smithee
  */
 
+#include "common/debug.h"
 #include "common/memstream.h"
+#include "common/rect.h"
 #include "common/textconsole.h"
 #include "graphics/yuv_to_rgb.h"
 #include "image/codecs/indeo4.h"
@@ -595,52 +597,233 @@ int Indeo4Decoder::decodeMbInfo(IVIBandDesc *band, IVITile *tile) {
 	return 0;
 }
 
-void Indeo4Decoder::decodeTransparency() {
-	// FIXME: Since I don't currently know how to decode the transparency layer,
-	// I'm currently doing a hack where I take the color of the top left corner,
-	// and mark the range of pixels of that color from the start and end of
-	// each line as transparent
-	assert(_surface->format.bytesPerPixel == 4);
-	byte r, g, b;
+int Indeo4Decoder::decodeRLETransparency(VLC_TYPE (*table)[2]) {
+	const uint32 startPos = _ctx._gb->pos();
+
+	_ctx._gb->align();
+
+	bool runIsOpaque = _ctx._gb->getBit();
+	bool nextRunIsOpaque = !runIsOpaque;
+
+	const uint32 opacityMask = 0xFF << _pixelFormat.aShift;
+
+	uint32 *pixel = (uint32 *)_surface->getPixels();
+	const int surfacePixelPitch = _surface->pitch / _surface->format.bytesPerPixel;
+	const int surfacePadding = surfacePixelPitch - _surface->w;
+	const uint32 *endOfVisibleRow = pixel + _surface->w;
+	const uint32 *endOfVisibleArea = pixel + surfacePixelPitch * _surface->h - surfacePadding;
+
+	const int codecAlignedWidth = (_surface->w + 31) & ~31;
+	const int codecPaddingSize = codecAlignedWidth - _surface->w;
+
+	int numPixelsToRead = codecAlignedWidth * _surface->h;
+	int numPixelsToSkip = 0;
+	while (numPixelsToRead > 0) {
+		int value = _ctx._gb->getVLC2<1>(table, IVI_VLC_BITS);
+
+		if (value == -1) {
+			warning("Transparency VLC code read failed");
+			return -1;
+		}
+
+		if (value == 0) {
+			value = 255;
+			nextRunIsOpaque = runIsOpaque;
+		}
+
+		numPixelsToRead -= value;
+
+		debugN(9, "%d%s ", value, runIsOpaque ? "O" : "T");
+
+		// The rest of the transparency data must be consumed but it will not
+		// participate in writing any more pixels
+		if (pixel == endOfVisibleArea) {
+			debug(5, "Indeo4: Done writing transparency, but still need to consume %d pixels", numPixelsToRead + value);
+			continue;
+		}
+
+		// If a run ends in the padding area of a row, the next run needs to
+		// be partially consumed by the remaining pixels of the padding area
+		if (numPixelsToSkip) {
+			value -= numPixelsToSkip;
+			if (value < 0) {
+				numPixelsToSkip = -value;
+				value = 0;
+			} else {
+				numPixelsToSkip = 0;
+			}
+		}
+
+		while (value > 0) {
+			if (runIsOpaque) {
+				*pixel = *pixel | opacityMask;
+			} else {
+				*pixel = *pixel & ~opacityMask;
+			}
+
+			--value;
+			++pixel;
+
+			if (pixel == endOfVisibleRow) {
+				pixel += surfacePadding;
+				endOfVisibleRow += surfacePixelPitch;
+				value -= codecPaddingSize;
+
+				if (value < 0) {
+					numPixelsToSkip = -value;
+					break;
+				}
+
+				if (pixel == endOfVisibleArea) {
+					break;
+				}
+			}
+		}
+
+		runIsOpaque = nextRunIsOpaque;
+		nextRunIsOpaque = !runIsOpaque;
+	}
+
+	debugN(9, "\n");
+
+	if (numPixelsToRead != 0) {
+		warning("Wrong number of transparency pixels read; delta = %d", numPixelsToRead);
+	}
+
+	_ctx._gb->align();
+
+	return (_ctx._gb->pos() - startPos) / 8;
+}
+
+int Indeo4Decoder::decodeTransparency() {
+	if (_ctx._gb->getBits(2) != 3 || _ctx._gb->getBits(3) != 0) {
+		warning("Invalid transparency marker");
+		return -1;
+	}
+
+	Common::Rect drawRect;
+
+	for (int numRects = _ctx._gb->getBits(8); numRects; --numRects) {
+		const int x1 = _ctx._gb->getBits(16);
+		const int y1 = _ctx._gb->getBits(16);
+		const int x2 = x1 + _ctx._gb->getBits(16);
+		const int y2 = y1 + _ctx._gb->getBits(16);
+		drawRect.extend(Common::Rect(x1, y1, x2, y2));
+	}
+
+	debug(4, "Indeo4: Transparency rect is (%d, %d, %d, %d)", drawRect.left, drawRect.top, drawRect.right, drawRect.bottom);
+
+	if (_ctx._gb->getBit()) { /* @350 */
+		/* @358 */
+		int unknown = (_ctx._gb->getBits(8) << 16) | (_ctx._gb->getBits(8) << 8) | (_ctx._gb->getBits(8));
+		debug(4, "Indeo4: Unknown is %08x", unknown);
+		/* @477 */
+		// This unknown value gets written out to IVIPicture.field_f8 and does
+		// not seem to have any obvious effect on the transparency rendering
+	}
+
+	if (_ctx._gb->getBit() == 0) { /* @4D9 */
+		warning("Invalid transparency band?");
+		return -1;
+	}
+
+	IVIHuffDesc huffDesc;
+
+	const int numHuffRows = huffDesc._numRows = _ctx._gb->getBits(4);
+	if (numHuffRows == 0 || numHuffRows > IVI_VLC_BITS - 1) {
+		warning("Invalid codebook row count %d", numHuffRows);
+		return -1;
+	}
+
+	for (int i = 0; i < numHuffRows; ++i) {
+		huffDesc._xBits[i] = _ctx._gb->getBits(4);
+	}
+
+	/* @5E2 */
+	_ctx._gb->align();
+
+	IVIHuffTab &huffTable = _ctx._transVlc;
+
+	if (huffDesc.huffDescCompare(&huffTable._custDesc) || !huffTable._custTab._table) {
+		if (huffTable._custTab._table) {
+			huffTable._custTab.freeVlc();
+		}
+
+		huffTable._custDesc = huffDesc;
+		huffTable._tabSel = 7;
+		huffTable._tab = &huffTable._custTab;
+		if (huffTable._custDesc.createHuffFromDesc(huffTable._tab, false)) {
+			// reset faulty description
+			huffTable._custDesc._numRows = 0;
+			warning("Error while initializing transparency VLC table");
+			return -1;
+		}
+	}
+
+	// FIXME: The transparency plane can be split, though it is not clear if
+	// this is in scalability mode, local decoding mode, or both. This adds
+	// complexity to the implementation, so avoid supporting unless it turns out
+	// to actually be necessary for correct decoding of game videos.
+	assert(!_ctx._isScalable);
+	assert(!_ctx._usesTiling);
 
 	if (_surface->format.aBits() == 0) {
 		// Surface is 4 bytes per pixel, but only RGB. So promote the
 		// surface to full RGBA, and convert all the existing pixels
-		Graphics::PixelFormat oldFormat = _pixelFormat;
 		_pixelFormat = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
-		_surface->format = _pixelFormat;
+		_surface->convertToInPlace(_pixelFormat);
+	}
 
-		for (int y = 0; y < _surface->h; ++y) {
-			uint32 *lineP = (uint32 *)_surface->getBasePtr(0, y);
-			for (int x = 0; x < _surface->w; ++x, ++lineP) {
-				oldFormat.colorToRGB(*lineP, r, g, b);
-				*lineP = _pixelFormat.ARGBToColor(0xff, r, g, b);
-			}
+	assert(_surface->format.bytesPerPixel == 4);
+	assert((_surface->pitch % 4) == 0);
+
+	const uint32 startByte = _ctx._gb->pos() / 8;
+
+	/* @68D */
+	const bool useFillTransparency = _ctx._gb->getBit();
+	if (useFillTransparency) {
+		/* @6F2 */
+		const bool runIsOpaque = _ctx._gb->getBit();
+		if (!runIsOpaque) {
+			// It should only be necessary to draw transparency here since the
+			// data from the YUV planes gets drawn to the output surface on each
+			// frame, which resets the surface pixels to be fully opaque
+			_surface->fillRect(Common::Rect(_surface->w, _surface->h), 0);
 		}
+
+		// No alignment here
 	} else {
-		// Working on a frame when the surface is already RGBA. In which case,
-		// start of by defaulting all pixels of the frame to fully opaque
-		for (int y = 0; y < _surface->h; ++y) {
-			uint32 *lineP = (uint32 *)_surface->getBasePtr(0, y);
-			for (int x = 0; x < _surface->w; ++x, ++lineP)
-				*lineP |= 0xff;
-		}
-	}
+		/* @7BF */
+		const bool hasDataSize = _ctx._gb->getBit();
+		if (hasDataSize) { /* @81A */
+			/* @822 */
+			int expectedSize = _ctx._gb->getBits(8);
+			if (expectedSize == 0xFF) {
+				expectedSize = _ctx._gb->getBits(24);
+			}
 
-	// Use the top-left pixel as the key color, and figure out the
-	// equivalent value as fully transparent
-	uint32 keyColor = *(const uint32 *)_surface->getPixels();
-	uint32 transColor = keyColor & ~0xff;
+			expectedSize -= ((_ctx._gb->pos() + 7) / 8) - startByte;
 
-	for (int y = 0; y < _surface->h; ++y) {
-		uint32 *startP = (uint32 *)_surface->getBasePtr(0, y);
-		uint32 *endP = (uint32 *)_surface->getBasePtr(_surface->w - 1, y);
+			const int bytesRead = decodeRLETransparency(huffTable._tab->_table);
+			if (bytesRead == -1) {
+				// A more specific warning should have been emitted already
+				return -1;
+			} else if (bytesRead != expectedSize) {
+				warning("Mismatched read %u != %u", bytesRead, expectedSize);
+				return -1;
+			}
+		} else {
+			/* @95B */
+			if (decodeRLETransparency(huffTable._tab->_table) == -1) {
+				warning("Transparency data read failure");
+				return -1;
+			}
+		}
 
-		while (startP <= endP && *startP == keyColor)
-			*startP++ = transColor;
-		while (endP > startP && *endP == keyColor)
-			*endP-- = transColor;
+		_ctx._gb->align();
 	}
+
+	return 0;
 }
 
 int Indeo4Decoder::scaleTileSize(int defSize, int sizeFactor) {
diff --git a/image/codecs/indeo4.h b/image/codecs/indeo4.h
index 8b7fdab..2f3fa8d 100644
--- a/image/codecs/indeo4.h
+++ b/image/codecs/indeo4.h
@@ -91,9 +91,14 @@ protected:
 	virtual int decodeMbInfo(IVIBandDesc *band, IVITile *tile);
 
 	/**
-	 * Decodes optional transparency data within Indeo frames
+	 * Decodes huffman + RLE-coded transparency data within Indeo4 frames
 	 */
-	virtual void decodeTransparency();
+	int decodeRLETransparency(VLC_TYPE (*table)[2]);
+
+	/**
+	 * Decodes optional transparency data within Indeo4 frames
+	 */
+	virtual int decodeTransparency();
 private:
 	int scaleTileSize(int defSize, int sizeFactor);
 


Commit: 7dd2c0342d9a650d6bdc4864c702921d3b3fb070
    https://github.com/scummvm/scummvm/commit/7dd2c0342d9a650d6bdc4864c702921d3b3fb070
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-08-24T20:34:19-05:00

Commit Message:
IMAGE: Remove unnecessary temporary surface in Indeo4/5

Changed paths:
    image/codecs/indeo/indeo.cpp


diff --git a/image/codecs/indeo/indeo.cpp b/image/codecs/indeo/indeo.cpp
index 6b6e355..f8cd8a1 100644
--- a/image/codecs/indeo/indeo.cpp
+++ b/image/codecs/indeo/indeo.cpp
@@ -578,8 +578,7 @@ int IndeoDecoderBase::decodeIndeoFrame() {
 	outputPlane(&_ctx._planes[1], frame->_data[2], frame->_linesize[2]);
 
 	// Merge the planes into the final surface
-	Graphics::Surface s = _surface->getSubArea(Common::Rect(0, 0, _surface->w, _surface->h));
-	YUVToRGBMan.convert410(&s, Graphics::YUVToRGBManager::kScaleITU,
+	YUVToRGBMan.convert410(_surface, Graphics::YUVToRGBManager::kScaleITU,
 		frame->_data[0], frame->_data[1], frame->_data[2], frame->_width, frame->_height,
 		frame->_width, frame->_width);
 


Commit: d39a9272bf0334e5e98801ba06df89b4f59b79b8
    https://github.com/scummvm/scummvm/commit/d39a9272bf0334e5e98801ba06df89b4f59b79b8
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-08-24T20:34:55-05:00

Commit Message:
IMAGE: Remove unnecessary extra heap allocation of Indeo surface

Changed paths:
    image/codecs/indeo/indeo.cpp
    image/codecs/indeo/indeo.h
    image/codecs/indeo4.cpp
    image/codecs/indeo5.cpp


diff --git a/image/codecs/indeo/indeo.cpp b/image/codecs/indeo/indeo.cpp
index f8cd8a1..27db365 100644
--- a/image/codecs/indeo/indeo.cpp
+++ b/image/codecs/indeo/indeo.cpp
@@ -479,15 +479,13 @@ IndeoDecoderBase::IndeoDecoderBase(uint16 width, uint16 height, uint bitsPerPixe
 		break;
 	}
 
-	_surface = new Graphics::Surface();
-	_surface->create(width, height, _pixelFormat);
-	_surface->fillRect(Common::Rect(0, 0, width, height), (bitsPerPixel == 32) ? 0xff : 0);
+	_surface.create(width, height, _pixelFormat);
+	_surface.fillRect(Common::Rect(0, 0, width, height), (bitsPerPixel == 32) ? 0xff : 0);
 	_ctx._bRefBuf = 3; // buffer 2 is used for scalability mode
 }
 
 IndeoDecoderBase::~IndeoDecoderBase() {
-	_surface->free();
-	delete _surface;
+	_surface.free();
 	IVIPlaneDesc::freeBuffers(_ctx._planes);
 	if (_ctx._mbVlc._custTab._table)
 		_ctx._mbVlc._custTab.freeVlc();
@@ -557,7 +555,7 @@ int IndeoDecoderBase::decodeIndeoFrame() {
 	if (!isNonNullFrame())
 		return 0;
 
-	assert(_ctx._planes[0]._width <= _surface->w && _ctx._planes[0]._height <= _surface->h);
+	assert(_ctx._planes[0]._width <= _surface.w && _ctx._planes[0]._height <= _surface.h);
 	result = frame->setDimensions(_ctx._planes[0]._width, _ctx._planes[0]._height);
 	if (result < 0)
 		return result;
@@ -578,7 +576,7 @@ int IndeoDecoderBase::decodeIndeoFrame() {
 	outputPlane(&_ctx._planes[1], frame->_data[2], frame->_linesize[2]);
 
 	// Merge the planes into the final surface
-	YUVToRGBMan.convert410(_surface, Graphics::YUVToRGBManager::kScaleITU,
+	YUVToRGBMan.convert410(&_surface, Graphics::YUVToRGBManager::kScaleITU,
 		frame->_data[0], frame->_data[1], frame->_data[2], frame->_width, frame->_height,
 		frame->_width, frame->_width);
 
diff --git a/image/codecs/indeo/indeo.h b/image/codecs/indeo/indeo.h
index 962d068..6c2a6b1 100644
--- a/image/codecs/indeo/indeo.h
+++ b/image/codecs/indeo/indeo.h
@@ -519,7 +519,7 @@ private:
 protected:
 	IVI45DecContext _ctx;
 	Graphics::PixelFormat _pixelFormat;
-	Graphics::Surface *_surface;
+	Graphics::Surface _surface;
 
 	/**
 	 *  Scan patterns shared between indeo4 and indeo5
diff --git a/image/codecs/indeo4.cpp b/image/codecs/indeo4.cpp
index 40f86f8..65aed6a 100644
--- a/image/codecs/indeo4.cpp
+++ b/image/codecs/indeo4.cpp
@@ -88,7 +88,7 @@ const Graphics::Surface *Indeo4Decoder::decodeFrame(Common::SeekableReadStream &
 	_ctx._frameData = nullptr;
 	_ctx._frameSize = 0;
 
-	return (err < 0) ? nullptr : _surface;
+	return (err < 0) ? nullptr : &_surface;
 }
 
 int Indeo4Decoder::decodePictureHeader() {
@@ -607,16 +607,16 @@ int Indeo4Decoder::decodeRLETransparency(VLC_TYPE (*table)[2]) {
 
 	const uint32 opacityMask = 0xFF << _pixelFormat.aShift;
 
-	uint32 *pixel = (uint32 *)_surface->getPixels();
-	const int surfacePixelPitch = _surface->pitch / _surface->format.bytesPerPixel;
-	const int surfacePadding = surfacePixelPitch - _surface->w;
-	const uint32 *endOfVisibleRow = pixel + _surface->w;
-	const uint32 *endOfVisibleArea = pixel + surfacePixelPitch * _surface->h - surfacePadding;
+	uint32 *pixel = (uint32 *)_surface.getPixels();
+	const int surfacePixelPitch = _surface.pitch / _surface.format.bytesPerPixel;
+	const int surfacePadding = surfacePixelPitch - _surface.w;
+	const uint32 *endOfVisibleRow = pixel + _surface.w;
+	const uint32 *endOfVisibleArea = pixel + surfacePixelPitch * _surface.h - surfacePadding;
 
-	const int codecAlignedWidth = (_surface->w + 31) & ~31;
-	const int codecPaddingSize = codecAlignedWidth - _surface->w;
+	const int codecAlignedWidth = (_surface.w + 31) & ~31;
+	const int codecPaddingSize = codecAlignedWidth - _surface.w;
 
-	int numPixelsToRead = codecAlignedWidth * _surface->h;
+	int numPixelsToRead = codecAlignedWidth * _surface.h;
 	int numPixelsToSkip = 0;
 	while (numPixelsToRead > 0) {
 		int value = _ctx._gb->getVLC2<1>(table, IVI_VLC_BITS);
@@ -774,8 +774,8 @@ int Indeo4Decoder::decodeTransparency() {
 		_surface->convertToInPlace(_pixelFormat);
 	}
 
-	assert(_surface->format.bytesPerPixel == 4);
-	assert((_surface->pitch % 4) == 0);
+	assert(_surface.format.bytesPerPixel == 4);
+	assert((_surface.pitch % 4) == 0);
 
 	const uint32 startByte = _ctx._gb->pos() / 8;
 
@@ -788,7 +788,7 @@ int Indeo4Decoder::decodeTransparency() {
 			// It should only be necessary to draw transparency here since the
 			// data from the YUV planes gets drawn to the output surface on each
 			// frame, which resets the surface pixels to be fully opaque
-			_surface->fillRect(Common::Rect(_surface->w, _surface->h), 0);
+			_surface.fillRect(Common::Rect(_surface.w, _surface.h), 0);
 		}
 
 		// No alignment here
diff --git a/image/codecs/indeo5.cpp b/image/codecs/indeo5.cpp
index c4e98d4..790bdec 100644
--- a/image/codecs/indeo5.cpp
+++ b/image/codecs/indeo5.cpp
@@ -97,7 +97,7 @@ const Graphics::Surface *Indeo5Decoder::decodeFrame(Common::SeekableReadStream &
 	_ctx._frameData = nullptr;
 	_ctx._frameSize = 0;
 
-	return (err < 0) ? nullptr : _surface;
+	return (err < 0) ? nullptr : &_surface;
 }
 
 int Indeo5Decoder::decodePictureHeader() {


Commit: 4a39f85c1b283fe17531cfab4ba9b0cb7a6bd928
    https://github.com/scummvm/scummvm/commit/4a39f85c1b283fe17531cfab4ba9b0cb7a6bd928
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-08-24T20:36:08-05:00

Commit Message:
IMAGE: Implement handling of key color in Indeo transparency

This should also improve performance by eliminating unnecessary
writes to the output bitmap for opaque pixels and by simplifying
the rendering loop.

Changed paths:
    image/codecs/indeo/indeo.cpp
    image/codecs/indeo/indeo.h
    image/codecs/indeo4.cpp


diff --git a/image/codecs/indeo/indeo.cpp b/image/codecs/indeo/indeo.cpp
index 27db365..3437753 100644
--- a/image/codecs/indeo/indeo.cpp
+++ b/image/codecs/indeo/indeo.cpp
@@ -444,7 +444,8 @@ IVI45DecContext::IVI45DecContext() : _gb(nullptr), _frameNum(0), _frameType(0),
 		_bRefBuf(0), _rvmapSel(0), _inImf(false), _inQ(false), _picGlobQuant(0),
 		_unknown1(0), _gopHdrSize(0), _gopFlags(0), _lockWord(0), _hasBFrames(false),
 		_hasTransp(false), _usesTiling(false), _usesHaar(false), _usesFullpel(false),
-		_gopInvalid(false), _isIndeo4(false), _pFrame(nullptr), _gotPFrame(false) {
+		_gopInvalid(false), _isIndeo4(false), _transKeyColor(0), _pFrame(nullptr),
+		_gotPFrame(false) {
 	Common::fill(&_bufInvalid[0], &_bufInvalid[4], 0);
 	Common::copy(&_ff_ivi_rvmap_tabs[0], &_ff_ivi_rvmap_tabs[9], &_rvmapTabs[0]);
 
diff --git a/image/codecs/indeo/indeo.h b/image/codecs/indeo/indeo.h
index 6c2a6b1..d9740ec 100644
--- a/image/codecs/indeo/indeo.h
+++ b/image/codecs/indeo/indeo.h
@@ -420,6 +420,7 @@ public:
 	int				_bufInvalid[4];
 
 	bool			_isIndeo4;
+	uint32			_transKeyColor;
 
 	AVFrame *		_pFrame;
 	bool			_gotPFrame;
diff --git a/image/codecs/indeo4.cpp b/image/codecs/indeo4.cpp
index 65aed6a..bc777cf 100644
--- a/image/codecs/indeo4.cpp
+++ b/image/codecs/indeo4.cpp
@@ -26,6 +26,7 @@
  * written, produced, and directed by Alan Smithee
  */
 
+#include "common/algorithm.h"
 #include "common/debug.h"
 #include "common/memstream.h"
 #include "common/rect.h"
@@ -111,6 +112,12 @@ int Indeo4Decoder::decodePictureHeader() {
 		_ctx._hasBFrames = true;
 
 	_ctx._hasTransp = _ctx._gb->getBit();
+	if (_ctx._hasTransp && _surface.format.aBits() == 0) {
+		// Surface is 4 bytes per pixel, but only RGB. So promote the
+		// surface to full RGBA, and convert all the existing pixels
+		_pixelFormat = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
+		_surface.convertToInPlace(_pixelFormat);
+	}
 
 	// unknown bit: Mac decoder ignores this bit, XANIM returns error
 	if (_ctx._gb->getBit()) {
@@ -605,8 +612,6 @@ int Indeo4Decoder::decodeRLETransparency(VLC_TYPE (*table)[2]) {
 	bool runIsOpaque = _ctx._gb->getBit();
 	bool nextRunIsOpaque = !runIsOpaque;
 
-	const uint32 opacityMask = 0xFF << _pixelFormat.aShift;
-
 	uint32 *pixel = (uint32 *)_surface.getPixels();
 	const int surfacePixelPitch = _surface.pitch / _surface.format.bytesPerPixel;
 	const int surfacePadding = surfacePixelPitch - _surface.w;
@@ -655,14 +660,12 @@ int Indeo4Decoder::decodeRLETransparency(VLC_TYPE (*table)[2]) {
 		}
 
 		while (value > 0) {
-			if (runIsOpaque) {
-				*pixel = *pixel | opacityMask;
-			} else {
-				*pixel = *pixel & ~opacityMask;
+			const int length = MIN<int>(value, endOfVisibleRow - pixel);
+			if (!runIsOpaque) {
+				Common::fill(pixel, pixel + length, _ctx._transKeyColor);
 			}
-
-			--value;
-			++pixel;
+			value -= length;
+			pixel += length;
 
 			if (pixel == endOfVisibleRow) {
 				pixel += surfacePadding;
@@ -715,11 +718,9 @@ int Indeo4Decoder::decodeTransparency() {
 
 	if (_ctx._gb->getBit()) { /* @350 */
 		/* @358 */
-		int unknown = (_ctx._gb->getBits(8) << 16) | (_ctx._gb->getBits(8) << 8) | (_ctx._gb->getBits(8));
-		debug(4, "Indeo4: Unknown is %08x", unknown);
+		_ctx._transKeyColor = _surface.format.ARGBToColor(0, _ctx._gb->getBits(8), _ctx._gb->getBits(8), _ctx._gb->getBits(8));
+		debug(4, "Indeo4: Key color is %08x", _ctx._transKeyColor);
 		/* @477 */
-		// This unknown value gets written out to IVIPicture.field_f8 and does
-		// not seem to have any obvious effect on the transparency rendering
 	}
 
 	if (_ctx._gb->getBit() == 0) { /* @4D9 */
@@ -767,13 +768,6 @@ int Indeo4Decoder::decodeTransparency() {
 	assert(!_ctx._isScalable);
 	assert(!_ctx._usesTiling);
 
-	if (_surface->format.aBits() == 0) {
-		// Surface is 4 bytes per pixel, but only RGB. So promote the
-		// surface to full RGBA, and convert all the existing pixels
-		_pixelFormat = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
-		_surface->convertToInPlace(_pixelFormat);
-	}
-
 	assert(_surface.format.bytesPerPixel == 4);
 	assert((_surface.pitch % 4) == 0);
 
@@ -788,7 +782,7 @@ int Indeo4Decoder::decodeTransparency() {
 			// It should only be necessary to draw transparency here since the
 			// data from the YUV planes gets drawn to the output surface on each
 			// frame, which resets the surface pixels to be fully opaque
-			_surface.fillRect(Common::Rect(_surface.w, _surface.h), 0);
+			_surface.fillRect(Common::Rect(_surface.w, _surface.h), _ctx._transKeyColor);
 		}
 
 		// No alignment here


Commit: 2b46eda5b67ccdca8ef9012020dea0766191fa16
    https://github.com/scummvm/scummvm/commit/2b46eda5b67ccdca8ef9012020dea0766191fa16
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-08-24T21:17:54-05:00

Commit Message:
IMAGE: Allow Indeo4 transparency decoding in scalable videos

y459.avi in Starship Titanic uses these two modes together, and
this appears to work fine.

Changed paths:
    image/codecs/indeo4.cpp


diff --git a/image/codecs/indeo4.cpp b/image/codecs/indeo4.cpp
index bc777cf..a4eba85 100644
--- a/image/codecs/indeo4.cpp
+++ b/image/codecs/indeo4.cpp
@@ -761,11 +761,12 @@ int Indeo4Decoder::decodeTransparency() {
 		}
 	}
 
-	// FIXME: The transparency plane can be split, though it is not clear if
-	// this is in scalability mode, local decoding mode, or both. This adds
-	// complexity to the implementation, so avoid supporting unless it turns out
-	// to actually be necessary for correct decoding of game videos.
-	assert(!_ctx._isScalable);
+	// FIXME: The transparency plane can be split, apparently for local decoding
+	// mode (y459.avi in Titanic has the scalable flag and its transparency
+	// plane seems to be decoded successfully, so the split transparency plane
+	// does not seem to be related to scaling mode). This adds complexity to the
+	// implementation, so avoid supporting unless it turns out to actually be
+	// necessary for correct decoding of game videos.
 	assert(!_ctx._usesTiling);
 
 	assert(_surface.format.bytesPerPixel == 4);


Commit: bb3fb4a963fd2e3abe6ed7c3eea60523ebd35093
    https://github.com/scummvm/scummvm/commit/bb3fb4a963fd2e3abe6ed7c3eea60523ebd35093
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2017-08-25T07:22:20-04:00

Commit Message:
Merge pull request #1000 from csnover/indeo4-transparency

IMAGE: Implement Indeo4 transparency

Changed paths:
    image/codecs/indeo/indeo.cpp
    image/codecs/indeo/indeo.h
    image/codecs/indeo4.cpp
    image/codecs/indeo4.h
    image/codecs/indeo5.cpp







More information about the Scummvm-git-logs mailing list