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

sev- noreply at scummvm.org
Sat Oct 1 08:58:51 UTC 2022


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:
9a71eb1a6d VIDEO: Avoid 64-bit math in Smacker bitstreams


Commit: 9a71eb1a6d819aac7aca2391a488942faf3e6f8f
    https://github.com/scummvm/scummvm/commit/9a71eb1a6d819aac7aca2391a488942faf3e6f8f
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2022-10-01T10:58:47+02:00

Commit Message:
VIDEO: Avoid 64-bit math in Smacker bitstreams

Changed paths:
    common/bitstream.h
    video/smk_decoder.cpp
    video/smk_decoder.h


diff --git a/common/bitstream.h b/common/bitstream.h
index d8d3c12a751..f1b1f5400cd 100644
--- a/common/bitstream.h
+++ b/common/bitstream.h
@@ -51,13 +51,13 @@ namespace Common {
  * for valueBits, isLE and isMSB2LSB, reads 32-bit little-endian values
  * from the data stream and hands out the bits in the order of LSB to MSB.
  */
-template<class STREAM, int valueBits, bool isLE, bool MSB2LSB>
+template<class STREAM, typename CONTAINER, int valueBits, bool isLE, bool MSB2LSB>
 class BitStreamImpl {
 private:
 	STREAM *_stream;			            //!< The input stream.
 	DisposeAfterUse::Flag _disposeAfterUse; //!< Whether to delete the stream on destruction.
 
-	uint64 _bitContainer;                   //!< The currently available bits.
+	CONTAINER _bitContainer;                //!< The currently available bits.
 	uint8  _bitsLeft;                       //!< Number of bits currently left in the bit container.
 	uint32 _size;                           //!< Total bit stream size (in bits).
 	uint32 _pos;                            //!< Current bit stream position (in bits).
@@ -88,7 +88,7 @@ private:
 	FORCEINLINE void fillContainer(size_t min) {
 		while (_bitsLeft < min) {
 
-			uint64 data;
+			CONTAINER data;
 			if (_pos + _bitsLeft + valueBits <= _size) {
 				data = readData();
 			} else {
@@ -102,7 +102,7 @@ private:
 
 			// Move the data value to the right position in the bit container
 			if (MSB2LSB)
-				_bitContainer |= data << (64 - valueBits - _bitsLeft);
+				_bitContainer |= data << ((sizeof(_bitContainer) * 8) - valueBits - _bitsLeft);
 			else
 				_bitContainer |= data << _bitsLeft;
 
@@ -111,11 +111,11 @@ private:
 }
 
 	/** Get @p n bits from the bit container. */
-	FORCEINLINE static uint32 getNBits(uint64 value, size_t n) {
+	FORCEINLINE static uint32 getNBits(CONTAINER value, size_t n) {
 		if (n == 0)
 			return 0;
 
-		const size_t toShift = 64 - n;
+		const size_t toShift = (sizeof(value) * 8) - n;
 
 		if (MSB2LSB)
 			return value >> toShift;
@@ -281,6 +281,11 @@ public:
 
 	/** Skip the specified number of bits. */
 	void skip(uint32 n) {
+		if (n >= _bitsLeft) {
+			n -= _bitsLeft;
+			skipBits(_bitsLeft);
+		}
+
 		while (n > 32) {
 			fillContainer(32);
 			skipBits(32);
@@ -300,12 +305,12 @@ public:
 	}
 
 	/** Return the stream position in bits. */
-	uint64 pos() const {
+	uint32 pos() const {
 		return _pos;
 	}
 
 	/** Return the stream size in bits. */
-	uint64 size() const {
+	uint32 size() const {
 		return _size;
 	}
 
@@ -360,11 +365,11 @@ public:
 		return false;
 	}
 
-	int64 pos() const {
+	uint32 pos() const {
 		return _pos;
 	}
 
-	int64 size() const {
+	uint32 size() const {
 		return _size;
 	}
 
@@ -469,52 +474,52 @@ public:
  */
 
 /** 8-bit data, MSB to LSB. */
-typedef BitStreamImpl<SeekableReadStream, 8, false, true > BitStream8MSB;
+typedef BitStreamImpl<SeekableReadStream, uint64, 8, false, true > BitStream8MSB;
 /** 8-bit data, LSB to MSB. */
-typedef BitStreamImpl<SeekableReadStream, 8, false, false> BitStream8LSB;
+typedef BitStreamImpl<SeekableReadStream, uint64, 8, false, false> BitStream8LSB;
 
 /** 16-bit little-endian data, MSB to LSB. */
-typedef BitStreamImpl<SeekableReadStream, 16, true , true > BitStream16LEMSB;
+typedef BitStreamImpl<SeekableReadStream, uint64, 16, true , true > BitStream16LEMSB;
 /** 16-bit little-endian data, LSB to MSB. */
-typedef BitStreamImpl<SeekableReadStream, 16, true , false> BitStream16LELSB;
+typedef BitStreamImpl<SeekableReadStream, uint64, 16, true , false> BitStream16LELSB;
 /** 16-bit big-endian data, MSB to LSB. */
-typedef BitStreamImpl<SeekableReadStream, 16, false, true > BitStream16BEMSB;
+typedef BitStreamImpl<SeekableReadStream, uint64, 16, false, true > BitStream16BEMSB;
 /** 16-bit big-endian data, LSB to MSB. */
-typedef BitStreamImpl<SeekableReadStream, 16, false, false> BitStream16BELSB;
+typedef BitStreamImpl<SeekableReadStream, uint64, 16, false, false> BitStream16BELSB;
 
 /** 32-bit little-endian data, MSB to LSB. */
-typedef BitStreamImpl<SeekableReadStream, 32, true , true > BitStream32LEMSB;
+typedef BitStreamImpl<SeekableReadStream, uint64, 32, true , true > BitStream32LEMSB;
 /** 32-bit little-endian data, LSB to MSB. */
-typedef BitStreamImpl<SeekableReadStream, 32, true , false> BitStream32LELSB;
+typedef BitStreamImpl<SeekableReadStream, uint64, 32, true , false> BitStream32LELSB;
 /** 32-bit big-endian data, MSB to LSB. */
-typedef BitStreamImpl<SeekableReadStream, 32, false, true > BitStream32BEMSB;
+typedef BitStreamImpl<SeekableReadStream, uint64, 32, false, true > BitStream32BEMSB;
 /** 32-bit big-endian data, LSB to MSB. */
-typedef BitStreamImpl<SeekableReadStream, 32, false, false> BitStream32BELSB;
+typedef BitStreamImpl<SeekableReadStream, uint64, 32, false, false> BitStream32BELSB;
 
 
 
 /** 8-bit data, MSB to LSB. */
-typedef BitStreamImpl<BitStreamMemoryStream, 8, false, true > BitStreamMemory8MSB;
+typedef BitStreamImpl<BitStreamMemoryStream, uint64, 8, false, true > BitStreamMemory8MSB;
 /** 8-bit data, LSB to MSB. */
-typedef BitStreamImpl<BitStreamMemoryStream, 8, false, false> BitStreamMemory8LSB;
+typedef BitStreamImpl<BitStreamMemoryStream, uint64, 8, false, false> BitStreamMemory8LSB;
 
 /** 16-bit little-endian data, MSB to LSB. */
-typedef BitStreamImpl<BitStreamMemoryStream, 16, true , true > BitStreamMemory16LEMSB;
+typedef BitStreamImpl<BitStreamMemoryStream, uint64, 16, true , true > BitStreamMemory16LEMSB;
 /** 16-bit little-endian data, LSB to MSB. */
-typedef BitStreamImpl<BitStreamMemoryStream, 16, true , false> BitStreamMemory16LELSB;
+typedef BitStreamImpl<BitStreamMemoryStream, uint64, 16, true , false> BitStreamMemory16LELSB;
 /** 16-bit big-endian data, MSB to LSB. */
-typedef BitStreamImpl<BitStreamMemoryStream, 16, false, true > BitStreamMemory16BEMSB;
+typedef BitStreamImpl<BitStreamMemoryStream, uint64, 16, false, true > BitStreamMemory16BEMSB;
 /** 16-bit big-endian data, LSB to MSB. */
-typedef BitStreamImpl<BitStreamMemoryStream, 16, false, false> BitStreamMemory16BELSB;
+typedef BitStreamImpl<BitStreamMemoryStream, uint64, 16, false, false> BitStreamMemory16BELSB;
 
 /** 32-bit little-endian data, MSB to LSB. */
-typedef BitStreamImpl<BitStreamMemoryStream, 32, true , true > BitStreamMemory32LEMSB;
+typedef BitStreamImpl<BitStreamMemoryStream, uint64, 32, true , true > BitStreamMemory32LEMSB;
 /** 32-bit little-endian data, LSB to MSB. */
-typedef BitStreamImpl<BitStreamMemoryStream, 32, true , false> BitStreamMemory32LELSB;
+typedef BitStreamImpl<BitStreamMemoryStream, uint64, 32, true , false> BitStreamMemory32LELSB;
 /** 32-bit big-endian data, MSB to LSB. */
-typedef BitStreamImpl<BitStreamMemoryStream, 32, false, true > BitStreamMemory32BEMSB;
+typedef BitStreamImpl<BitStreamMemoryStream, uint64, 32, false, true > BitStreamMemory32BEMSB;
 /** 32-bit big-endian data, LSB to MSB. */
-typedef BitStreamImpl<BitStreamMemoryStream, 32, false, false> BitStreamMemory32BELSB;
+typedef BitStreamImpl<BitStreamMemoryStream, uint64, 32, false, false> BitStreamMemory32BELSB;
 
 /** @} */
 
diff --git a/video/smk_decoder.cpp b/video/smk_decoder.cpp
index e918f23d118..5f6f096d2d5 100644
--- a/video/smk_decoder.cpp
+++ b/video/smk_decoder.cpp
@@ -53,9 +53,9 @@ enum SmkBlockTypes {
 
 class SmallHuffmanTree {
 public:
-	SmallHuffmanTree(Common::BitStreamMemory8LSB &bs);
+	SmallHuffmanTree(SmackerBitStream &bs);
 
-	uint16 getCode(Common::BitStreamMemory8LSB &bs);
+	uint16 getCode(SmackerBitStream &bs);
 private:
 	enum {
 		SMK_NODE = 0x8000
@@ -69,11 +69,11 @@ private:
 	uint16 _prefixtree[256];
 	byte _prefixlength[256];
 
-	Common::BitStreamMemory8LSB &_bs;
+	SmackerBitStream &_bs;
 	bool _empty;
 };
 
-SmallHuffmanTree::SmallHuffmanTree(Common::BitStreamMemory8LSB &bs)
+SmallHuffmanTree::SmallHuffmanTree(SmackerBitStream &bs)
 	: _treeSize(0), _bs(bs), _empty(false) {
 	if (!_bs.getBit()) {
 		_empty = true;
@@ -122,7 +122,7 @@ uint16 SmallHuffmanTree::decodeTree(uint32 prefix, int length) {
 	return r1+r2+1;
 }
 
-uint16 SmallHuffmanTree::getCode(Common::BitStreamMemory8LSB &bs) {
+uint16 SmallHuffmanTree::getCode(SmackerBitStream &bs) {
 	if (_empty)
 		return 0;
 
@@ -149,11 +149,11 @@ uint16 SmallHuffmanTree::getCode(Common::BitStreamMemory8LSB &bs) {
 
 class BigHuffmanTree {
 public:
-	BigHuffmanTree(Common::BitStreamMemory8LSB &bs, int allocSize);
+	BigHuffmanTree(SmackerBitStream &bs, int allocSize);
 	~BigHuffmanTree();
 
 	void reset();
-	uint32 getCode(Common::BitStreamMemory8LSB &bs);
+	uint32 getCode(SmackerBitStream &bs);
 private:
 	enum {
 		SMK_NODE = 0x80000000
@@ -169,13 +169,13 @@ private:
 	byte _prefixlength[256];
 
 	/* Used during construction */
-	Common::BitStreamMemory8LSB &_bs;
+	SmackerBitStream &_bs;
 	uint32 _markers[3];
 	SmallHuffmanTree *_loBytes;
 	SmallHuffmanTree *_hiBytes;
 };
 
-BigHuffmanTree::BigHuffmanTree(Common::BitStreamMemory8LSB &bs, int allocSize)
+BigHuffmanTree::BigHuffmanTree(SmackerBitStream &bs, int allocSize)
 	: _bs(bs) {
 	uint32 bit = _bs.getBit();
 	if (!bit) {
@@ -265,7 +265,7 @@ uint32 BigHuffmanTree::decodeTree(uint32 prefix, int length) {
 	return r1+r2+1;
 }
 
-uint32 BigHuffmanTree::getCode(Common::BitStreamMemory8LSB &bs) {
+uint32 BigHuffmanTree::getCode(SmackerBitStream &bs) {
 	// Peeking data out of bounds is well-defined and returns 0 bits.
 	// This is for convenience when using speed-up techniques reading
 	// more bits than actually available.
@@ -413,7 +413,7 @@ bool SmackerDecoder::loadStream(Common::SeekableReadStream *stream) {
 	byte *huffmanTrees = (byte *) malloc(_header.treesSize);
 	_fileStream->read(huffmanTrees, _header.treesSize);
 
-	Common::BitStreamMemory8LSB bs(new Common::BitStreamMemoryStream(huffmanTrees, _header.treesSize, DisposeAfterUse::YES), DisposeAfterUse::YES);
+	SmackerBitStream bs(new Common::BitStreamMemoryStream(huffmanTrees, _header.treesSize, DisposeAfterUse::YES), DisposeAfterUse::YES);
 	videoTrack->readTrees(bs, _header.mMapSize, _header.mClrSize, _header.fullSize, _header.typeSize);
 
 	_firstFrameStart = _fileStream->pos();
@@ -539,7 +539,7 @@ void SmackerDecoder::readNextPacket() {
 
 	_fileStream->read(frameData, frameDataSize);
 
-	Common::BitStreamMemory8LSB bs(new Common::BitStreamMemoryStream(frameData, frameDataSize + 1, DisposeAfterUse::YES), DisposeAfterUse::YES);
+	SmackerBitStream bs(new Common::BitStreamMemoryStream(frameData, frameDataSize + 1, DisposeAfterUse::YES), DisposeAfterUse::YES);
 	videoTrack->decodeFrame(bs);
 
 	_fileStream->seek(startPos + frameSize);
@@ -624,14 +624,14 @@ Graphics::PixelFormat SmackerDecoder::SmackerVideoTrack::getPixelFormat() const
 	return _surface->format;
 }
 
-void SmackerDecoder::SmackerVideoTrack::readTrees(Common::BitStreamMemory8LSB &bs, uint32 mMapSize, uint32 mClrSize, uint32 fullSize, uint32 typeSize) {
+void SmackerDecoder::SmackerVideoTrack::readTrees(SmackerBitStream &bs, uint32 mMapSize, uint32 mClrSize, uint32 fullSize, uint32 typeSize) {
 	_MMapTree = new BigHuffmanTree(bs, mMapSize);
 	_MClrTree = new BigHuffmanTree(bs, mClrSize);
 	_FullTree = new BigHuffmanTree(bs, fullSize);
 	_TypeTree = new BigHuffmanTree(bs, typeSize);
 }
 
-void SmackerDecoder::SmackerVideoTrack::decodeFrame(Common::BitStreamMemory8LSB &bs) {
+void SmackerDecoder::SmackerVideoTrack::decodeFrame(SmackerBitStream &bs) {
 	_MMapTree->reset();
 	_MClrTree->reset();
 	_FullTree->reset();
@@ -853,7 +853,7 @@ Audio::AudioStream *SmackerDecoder::SmackerAudioTrack::getAudioStream() const {
 }
 
 void SmackerDecoder::SmackerAudioTrack::queueCompressedBuffer(byte *buffer, uint32 bufferSize, uint32 unpackedSize) {
-	Common::BitStreamMemory8LSB audioBS(new Common::BitStreamMemoryStream(buffer, bufferSize), DisposeAfterUse::YES);
+	SmackerBitStream audioBS(new Common::BitStreamMemoryStream(buffer, bufferSize), DisposeAfterUse::YES);
 	bool dataPresent = audioBS.getBit();
 
 	if (!dataPresent)
diff --git a/video/smk_decoder.h b/video/smk_decoder.h
index 3b1f910b5e8..c913daebab8 100644
--- a/video/smk_decoder.h
+++ b/video/smk_decoder.h
@@ -43,6 +43,11 @@ namespace Video {
 
 class BigHuffmanTree;
 
+// Because the maximum number of bits read from a bitstream is 16, and the data is 8-bit, the container only
+// needs to hold up to 23 bits at any given time. As such, we use a bitstream with a 32-bit container to
+// avoid the overhead of 64-bit maths on systems that don't support it natively.
+typedef Common::BitStreamImpl<Common::BitStreamMemoryStream, uint32, 8, false, false> SmackerBitStream;
+
 /**
  * Decoder for Smacker v2/v4 videos.
  *
@@ -100,9 +105,9 @@ protected:
 		const byte *getPalette() const { _dirtyPalette = false; return _palette; }
 		bool hasDirtyPalette() const { return _dirtyPalette; }
 
-		void readTrees(Common::BitStreamMemory8LSB &bs, uint32 mMapSize, uint32 mClrSize, uint32 fullSize, uint32 typeSize);
+		void readTrees(SmackerBitStream &bs, uint32 mMapSize, uint32 mClrSize, uint32 fullSize, uint32 typeSize);
 		void increaseCurFrame() { _curFrame++; }
-		void decodeFrame(Common::BitStreamMemory8LSB &bs);
+		void decodeFrame(SmackerBitStream &bs);
 		void unpackPalette(Common::SeekableReadStream *stream);
 
 		Common::Rational getFrameRate() const { return _frameRate; }




More information about the Scummvm-git-logs mailing list