[Scummvm-git-logs] scummvm master -> 47755b4b38e7e912b1b961ba82019fe37b9e0957

bluegr noreply at scummvm.org
Sat Aug 27 21:05:35 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:
47755b4b38 COMMON: Make better use of inlining in BitStream functions


Commit: 47755b4b38e7e912b1b961ba82019fe37b9e0957
    https://github.com/scummvm/scummvm/commit/47755b4b38e7e912b1b961ba82019fe37b9e0957
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2022-08-28T00:05:31+03:00

Commit Message:
COMMON: Make better use of inlining in BitStream functions

Changed paths:
    audio/decoders/qdm2.cpp
    audio/decoders/wma.cpp
    common/bitstream.h
    common/stuffit.cpp
    engines/macventure/image.cpp
    engines/macventure/text.cpp
    image/codecs/indeo/get_bits.h
    image/codecs/indeo/indeo.cpp
    image/codecs/indeo4.cpp
    image/codecs/indeo5.cpp
    image/codecs/jyv1.cpp
    image/codecs/svq1.cpp
    video/bink_decoder.cpp
    video/bink_decoder.h
    video/psx_decoder.cpp
    video/smk_decoder.cpp


diff --git a/audio/decoders/qdm2.cpp b/audio/decoders/qdm2.cpp
index b7a1ed6986b..f346876cf9f 100644
--- a/audio/decoders/qdm2.cpp
+++ b/audio/decoders/qdm2.cpp
@@ -1225,7 +1225,7 @@ static int qdm2_get_vlc(Common::BitStreamMemory32LELSB *gb, VLC *vlc, int flag,
 
 	// stage-2, 3 bits exponent escape sequence
 	if (value-- == 0)
-		value = gb->getBits(gb->getBits(3) + 1);
+		value = gb->getBits(gb->getBits<3>() + 1);
 
 	// stage-3, optional
 	if (flag) {
@@ -1664,7 +1664,7 @@ void QDM2Stream::synthfilt_build_sb_samples(Common::BitStreamMemory32LELSB *gb,
 									samples[2 * k] = gb->getBit() ? dequant_1bit[joined_stereo][2 * gb->getBit()] : 0;
 								}
 							} else {
-								n = gb->getBits(8);
+								n = gb->getBits<8>();
 								for (k = 0; k < 5; k++)
 									samples[2 * k] = dequant_1bit[joined_stereo][_randomDequantIndex[n][k]];
 							}
@@ -1700,7 +1700,7 @@ void QDM2Stream::synthfilt_build_sb_samples(Common::BitStreamMemory32LELSB *gb,
 									samples[k] = (gb->getBit() == 0) ? 0 : dequant_1bit[joined_stereo][2 * gb->getBit()];
 								}
 							} else {
-								n = gb->getBits(8);
+								n = gb->getBits<8>();
 								for (k = 0; k < 5; k++)
 									samples[k] = dequant_1bit[joined_stereo][_randomDequantIndex[n][k]];
 							}
@@ -1713,7 +1713,7 @@ void QDM2Stream::synthfilt_build_sb_samples(Common::BitStreamMemory32LELSB *gb,
 
 					case 24:
 						if ((length - gb->pos()) >= 7) {
-							n = gb->getBits(7);
+							n = gb->getBits<7>();
 							for (k = 0; k < 3; k++)
 								samples[k] = (_randomDequantType24[n][k] - 2.0) * 0.5;
 						} else {
@@ -1735,8 +1735,8 @@ void QDM2Stream::synthfilt_build_sb_samples(Common::BitStreamMemory32LELSB *gb,
 					case 34:
 						if ((length - gb->pos()) >= 7) {
 							if (type34_first) {
-								type34_div = (float)(1 << gb->getBits(2));
-								samples[0] = ((float)gb->getBits(5) - 16.0) / 15.0;
+								type34_div = (float)(1 << gb->getBits<2>());
+								samples[0] = ((float)gb->getBits<5>() - 16.0) / 15.0;
 								type34_predictor = samples[0];
 								type34_first = 0;
 							} else {
@@ -1943,7 +1943,7 @@ void QDM2Stream::process_subpacket_11(QDM2SubPNode *node, int length) {
 	Common::BitStreamMemory32LELSB gb(&d);
 
 	if (length >= 32) {
-		int c = gb.getBits(13);
+		int c = gb.getBits<13>();
 
 		if (c > 3)
 			fill_coding_method_array(_toneLevelIdx, _toneLevelIdxTemp, _codingMethod,
@@ -2018,22 +2018,22 @@ void QDM2Stream::qdm2_decode_super_block(void) {
 	Common::BitStreamMemoryStream packetStream(_compressedData, _packetSize + FF_INPUT_BUFFER_PADDING_SIZE);
 	Common::BitStreamMemory32LELSB packetBitStream(packetStream);
 	//qdm2_decode_sub_packet_header
-	header.type = packetBitStream.getBits(8);
+	header.type = packetBitStream.getBits<8>();
 
 	if (header.type == 0) {
 		header.size = 0;
 		header.data = NULL;
 	} else {
-		header.size = packetBitStream.getBits(8);
+		header.size = packetBitStream.getBits<8>();
 
 		if (header.type & 0x80) {
 			header.size <<= 8;
-			header.size |= packetBitStream.getBits(8);
+			header.size |= packetBitStream.getBits<8>();
 			header.type &= 0x7f;
 		}
 
 		if (header.type == 0x7f)
-			header.type |= (packetBitStream.getBits(8) << 8);
+			header.type |= (packetBitStream.getBits<8>() << 8);
 
 		header.data = &_compressedData[packetBitStream.pos() / 8];
 	}
@@ -2051,7 +2051,7 @@ void QDM2Stream::qdm2_decode_super_block(void) {
 	Common::BitStreamMemory32LELSB headerBitStream(headerStream);
 
 	if (header.type == 2 || header.type == 4 || header.type == 5) {
-		int csum = 257 * headerBitStream.getBits(8) + 2 * headerBitStream.getBits(8);
+		int csum = 257 * headerBitStream.getBits<8>() + 2 * headerBitStream.getBits<8>();
 
 		csum = qdm2_packet_checksum(_compressedData, _packetSize, csum);
 
@@ -2087,22 +2087,22 @@ void QDM2Stream::qdm2_decode_super_block(void) {
 		// decode subpacket
 		packet = &_subPackets[i];
 		//qdm2_decode_sub_packet_header
-		packet->type = headerBitStream.getBits(8);
+		packet->type = headerBitStream.getBits<8>();
 
 		if (packet->type == 0) {
 			packet->size = 0;
 			packet->data = NULL;
 		} else {
-			packet->size = headerBitStream.getBits(8);
+			packet->size = headerBitStream.getBits<8>();
 
 			if (packet->type & 0x80) {
 				packet->size <<= 8;
-				packet->size |= headerBitStream.getBits(8);
+				packet->size |= headerBitStream.getBits<8>();
 				packet->type &= 0x7f;
 			}
 
 			if (packet->type == 0x7f)
-				packet->type |= (headerBitStream.getBits(8) << 8);
+				packet->type |= (headerBitStream.getBits<8>() << 8);
 
 			packet->data = &header.data[headerBitStream.pos() / 8];
 		}
@@ -2133,7 +2133,7 @@ void QDM2Stream::qdm2_decode_super_block(void) {
 			QDM2_LIST_ADD(_subPacketListD, subPacketsD, packet);
 		} else if (packet->type == 13) {
 			for (j = 0; j < 6; j++)
-				_fftLevelExp[j] = headerBitStream.getBits(6);
+				_fftLevelExp[j] = headerBitStream.getBits<6>();
 		} else if (packet->type == 14) {
 			for (j = 0; j < 6; j++)
 				_fftLevelExp[j] = qdm2_get_vlc(&headerBitStream, &_fftLevelExpVlc, 0, 2);
@@ -2223,7 +2223,7 @@ void QDM2Stream::qdm2_fft_decode_tones(int duration, Common::BitStreamMemory32LE
 		exp += _fftLevelExp[fft_level_index_table[local_int_14]];
 		exp = (exp < 0) ? 0 : exp;
 
-		phase = gb->getBits(3);
+		phase = gb->getBits<3>();
 		stereo_exp = 0;
 		stereo_phase = 0;
 
@@ -2302,7 +2302,7 @@ void QDM2Stream::qdm2_decode_fft_packets(void) {
 			}
 		} else if (type == 46) {
 			for (j=0; j < 6; j++)
-				_fftLevelExp[j] = gb.getBits(6);
+				_fftLevelExp[j] = gb.getBits<6>();
 			for (j=0; j < 4; j++) {
 				qdm2_fft_decode_tones(j, &gb, unknown_flag);
 			}
diff --git a/audio/decoders/wma.cpp b/audio/decoders/wma.cpp
index ef20bf332d3..6014d5f6ecb 100644
--- a/audio/decoders/wma.cpp
+++ b/audio/decoders/wma.cpp
@@ -571,7 +571,7 @@ Common::SeekableReadStream *WMACodec::decodeSuperFrame(Common::SeekableReadStrea
 		bits.skip(4); // Super frame index
 
 		// Number of frames in this superframe
-		int newFrameCount = bits.getBits(4) - 1;
+		int newFrameCount = bits.getBits<4>() - 1;
 		if (newFrameCount < 0) {
 			warning("WMACodec::decodeSuperFrame(): newFrameCount == %d", newFrameCount);
 
@@ -603,7 +603,7 @@ Common::SeekableReadStream *WMACodec::decodeSuperFrame(Common::SeekableReadStrea
 			byte *lastSuperframeEnd = _lastSuperframe + _lastSuperframeLen;
 
 			while (bitOffset > 7) { // Full bytes
-				*lastSuperframeEnd++ = bits.getBits(8);
+				*lastSuperframeEnd++ = bits.getBits<8>();
 
 				bitOffset          -= 8;
 				_lastSuperframeLen += 1;
@@ -936,7 +936,7 @@ bool WMACodec::decodeNoise(Common::BitStream8MSB &bits, int bSize,
 				val += code - 18;
 
 			} else
-				val = bits.getBits(7) - 19;
+				val = bits.getBits<7>() - 19;
 
 			_highBandValues[i][j] = val;
 
@@ -1223,7 +1223,7 @@ bool WMACodec::decodeExpHuffman(Common::BitStream8MSB &bits, int ch) {
 	int lastExp;
 	if (_version == 1) {
 
-		lastExp = bits.getBits(5) + 10;
+		lastExp = bits.getBits<5>() + 10;
 
 		float   v = ptab[lastExp];
 		uint32 iv = iptab[lastExp];
@@ -1314,9 +1314,9 @@ bool WMACodec::decodeExpLSP(Common::BitStream8MSB &bits, int ch) {
 		int val;
 
 		if (i == 0 || i >= 8)
-			val = bits.getBits(3);
+			val = bits.getBits<3>();
 		else
-			val = bits.getBits(4);
+			val = bits.getBits<4>();
 
 		lspCoefs[i] = lspCodebook[i][val];
 	}
@@ -1374,7 +1374,7 @@ bool WMACodec::decodeRunLevel(Common::BitStream8MSB &bits, const HuffmanDecoder
 						} else
 							offset += bits.getBits(frameLenBits) + 4;
 					} else
-						offset += bits.getBits(2) + 1;
+						offset += bits.getBits<2>() + 1;
 				}
 
 			}
@@ -1472,7 +1472,7 @@ int WMACodec::readTotalGain(Common::BitStream8MSB &bits) {
 
 	int v = 127;
 	while (v == 127) {
-		v = bits.getBits(7);
+		v = bits.getBits<7>();
 
 		totalGain += v;
 	}
@@ -1491,19 +1491,19 @@ int WMACodec::totalGainToBits(int totalGain) {
 uint32 WMACodec::getLargeVal(Common::BitStream8MSB &bits) {
 	// Consumes up to 34 bits
 
-	int count = 8;
 	if (bits.getBit()) {
-		count += 8;
-
 		if (bits.getBit()) {
-			count += 8;
-
-			if (bits.getBit())
-				count += 7;
+			if (bits.getBit()) {
+				return bits.getBits<31>();
+			} else {
+				return bits.getBits<24>();
+			}
+		} else {
+			return bits.getBits<16>();
 		}
+	} else {
+		return bits.getBits<8>();
 	}
-
-	return bits.getBits(count);
 }
 
 } // End of namespace Audio
diff --git a/common/bitstream.h b/common/bitstream.h
index 0b0a653d11a..d8d3c12a751 100644
--- a/common/bitstream.h
+++ b/common/bitstream.h
@@ -63,7 +63,7 @@ private:
 	uint32 _pos;                            //!< Current bit stream position (in bits).
 
 	/** Read a data value. */
-	inline uint32 readData() {
+	FORCEINLINE uint32 readData() {
 		if (isLE) {
 			if (valueBits ==  8)
 				return _stream->readByte();
@@ -85,7 +85,7 @@ private:
 	}
 
 	/** Fill the container with at least @p min bits. */
-	inline void fillContainer(size_t min) {
+	FORCEINLINE void fillContainer(size_t min) {
 		while (_bitsLeft < min) {
 
 			uint64 data;
@@ -111,7 +111,7 @@ private:
 }
 
 	/** Get @p n bits from the bit container. */
-	inline static uint32 getNBits(uint64 value, size_t n) {
+	FORCEINLINE static uint32 getNBits(uint64 value, size_t n) {
 		if (n == 0)
 			return 0;
 
@@ -124,7 +124,7 @@ private:
 	}
 
 	/** Skip already read bits. */
-	inline void skipBits(size_t n) {
+	FORCEINLINE void skipBits(size_t n) {
 		assert(n <= _bitsLeft);
 
 		// Shift to the next bit
@@ -179,6 +179,42 @@ public:
 		return b;
 	}
 
+	/**
+	 * Read a multi-bit value from the bit stream, without changing the stream's position.
+	 *
+	 * The bit order is the same as in @ref getBits().
+	 */
+	template<int n>
+	uint32 peekBits() {
+		if (n > 32)
+			error("BitStreamImpl::peekBits(): Too many bits requested to be peeked");
+
+		fillContainer(n);
+		return getNBits(_bitContainer, n);
+	}
+
+	/**
+	 * Read a multi-bit value from the bit stream.
+	 *
+	 * The value is read as if just taken as a whole from the bit stream.
+	 *
+	 * For example:
+	 * Reading a 4-bit value from an 8-bit bit stream with the contents 01010011:
+	 * If the bit stream is MSB2LSB, the 4-bit value would be 0101.
+	 * If the bit stream is LSB2MSB, the 4-bit value would be 0011.
+	 */
+	template<int n>
+	uint32 getBits() {
+		if (n > 32)
+			error("BitStreamImpl::getBits(): Too many bits requested to be read");
+
+		const uint32 b = peekBits<n>();
+
+		skipBits(n);
+
+		return b;
+	}
+
 	/**
 	 * Read a multi-bit value from the bit stream, without changing the stream's position.
 	 *
diff --git a/common/stuffit.cpp b/common/stuffit.cpp
index 63408ea36f6..97ff1dcab96 100644
--- a/common/stuffit.cpp
+++ b/common/stuffit.cpp
@@ -313,13 +313,13 @@ struct SIT14Data {
 void StuffItArchive::readTree14(Common::BitStream8LSB *bits, SIT14Data *dat, uint16 codesize, uint16 *result) const {
 	uint32 i, l, n;
 	uint32 k = bits->getBit();
-	uint32 j = bits->getBits(2) + 2;
-	uint32 o = bits->getBits(3) + 1;
+	uint32 j = bits->getBits<2>() + 2;
+	uint32 o = bits->getBits<3>() + 1;
 	uint32 size = 1 << j;
 	uint32 m = size - 1;
 	k = k ? (m - 1) : 0xFFFFFFFF;
 
-	if (bits->getBits(2) & 1) { // skip 1 bit!
+	if (bits->getBits<2>() & 1) { // skip 1 bit!
 		// requirements for this call: dat->buff[32], dat->code[32], dat->freq[32*2]
 		readTree14(bits, dat, size, dat->freq);
 
@@ -471,14 +471,14 @@ Common::SeekableReadStream *StuffItArchive::decompress14(Common::SeekableReadStr
 			for (j = 0; j < m; ++j)
 				dat->var6[i++] = l;
 
-	m = bits->getBits(16); // number of blocks
+	m = bits->getBits<16>(); // number of blocks
 	j = 0; // window position
 
 	while (m-- && !bits->eos()) {
-		bits->getBits(16); // skip crunched block size
-		bits->getBits(16);
-		n = bits->getBits(16); // number of uncrunched bytes
-		n |= bits->getBits(16) << 16;
+		bits->getBits<16>(); // skip crunched block size
+		bits->getBits<16>();
+		n = bits->getBits<16>(); // number of uncrunched bytes
+		n |= bits->getBits<16>() << 16;
 		readTree14(bits, dat, 308, dat->var7);
 		readTree14(bits, dat, 75, dat->var3);
 
diff --git a/engines/macventure/image.cpp b/engines/macventure/image.cpp
index bcb33f672c4..799e309833e 100644
--- a/engines/macventure/image.cpp
+++ b/engines/macventure/image.cpp
@@ -114,18 +114,18 @@ void ImageAsset::decodePPIC(ObjID id, Common::Array<byte> &data, uint &bitHeight
 	Common::SeekableReadStream *baseStream = _container->getItem(realID);
 	Common::BitStream32BEMSB stream(baseStream);
 
-	uint8 mode = stream.getBits(3);
+	uint8 mode = stream.getBits<3>();
 	int w, h;
 	if (stream.getBit()) {
-		h = stream.getBits(10);
+		h = stream.getBits<10>();
 	} else {
-		h = stream.getBits(6);
+		h = stream.getBits<6>();
 	}
 
 	if (stream.getBit()) {
-		w = stream.getBits(10);
+		w = stream.getBits<10>();
 	} else {
-		w = stream.getBits(6);
+		w = stream.getBits<6>();
 	}
 
 	rowBytes = ((w + 0xF) >> 3) & 0xFFFE;
@@ -164,7 +164,7 @@ void ImageAsset::decodePPIC0(Common::BitStream32BEMSB &stream, Common::Array<byt
 	uint p = 0;
 	for (uint y = 0; y < bitHeight; y++) {
 		for (uint x = 0; x < words; x++) {
-			v = stream.peekBits(32);
+			v = stream.peekBits<32>();
 			stream.skip(16);
 			v >>= 16 - (stream.pos() % 8);
 			data[p] = (v >> 8) & 0xff; p++;
@@ -217,7 +217,7 @@ void ImageAsset::decodePPIC3(Common::BitStream32BEMSB &stream, Common::Array<byt
 		}
 	}
 
-	bits = stream.getBits(2) + 1;
+	bits = stream.getBits<2>() + 1;
 	uint16 mask = 0;
 	for (uint i = 0; i < 0xf; i++) {
 		if (i) {
@@ -245,9 +245,9 @@ void ImageAsset::decodeHuffGraphic(const PPICHuff &huff, Common::BitStream32BEMS
 	_walkRepeat = 0;
 	_walkLast = 0;
 	if (bitWidth & 3) {
-		flags = stream.getBits(5);
+		flags = stream.getBits<5>();
 	} else {
-		flags = stream.getBits(4) << 1;
+		flags = stream.getBits<4>() << 1;
 	}
 
 	byte odd = 0;
@@ -341,7 +341,7 @@ byte ImageAsset::walkHuff(const PPICHuff &huff, Common::BitStream32BEMSB &stream
 		_walkLast = ((_walkLast << 8) & 0xFF00) | (_walkLast >> 8);
 		return _walkLast & 0xFF;
 	}
-	uint16 dw = stream.peekBits(16);
+	uint16 dw = stream.peekBits<16>();
 	uint16 i = 0;
 	for (;i < 16; i++) {
 		if (huff.masks[i + 1] > dw) {
@@ -355,13 +355,13 @@ byte ImageAsset::walkHuff(const PPICHuff &huff, Common::BitStream32BEMSB &stream
 			_walkLast &= 0xFF;
 			_walkLast |= _walkLast << 8;
 		}
-		_walkRepeat = stream.getBits(3);
+		_walkRepeat = stream.getBits<3>();
 		if (_walkRepeat < 3) {
 			_walkRepeat <<= 4;
-			_walkRepeat |= stream.getBits(4);
+			_walkRepeat |= stream.getBits<4>();
 			if (_walkRepeat < 8) {
 				_walkRepeat <<= 8;
-				_walkRepeat |= stream.getBits(8);
+				_walkRepeat |= stream.getBits<8>();
 			}
 		}
 		_walkRepeat -= 2;
diff --git a/engines/macventure/text.cpp b/engines/macventure/text.cpp
index 7e15dc82519..3949c9d0768 100644
--- a/engines/macventure/text.cpp
+++ b/engines/macventure/text.cpp
@@ -54,7 +54,7 @@ void TextAsset::decodeOld() {
 	bool lowercase = false;
 	char c = ' ';
 	for (uint16 i = 0; i < strLen; i++) {
-		char val = stream.getBits(5);
+		char val = stream.getBits<5>();
 		if (val == 0x0) { // Space
 			c = ' ';
 		} else if (val >= 0x1 && val <= 0x1A) {
@@ -79,7 +79,7 @@ void TextAsset::decodeOld() {
 			}
 			lowercase = true;
 		} else if (val == 0x1D) { // Composite
-			ObjID subval = stream.getBits(16);
+			ObjID subval = stream.getBits<16>();
 			Common::String child;
 			if (subval & 0x8000) {
 				// Composite object id
@@ -95,7 +95,7 @@ void TextAsset::decodeOld() {
 			}
 			lowercase = true;
 		} else if (val == 0x1E) {
-			c = stream.getBits(8);
+			c = stream.getBits<8>();
 			lowercase = true;
 		} else if (val == 0x1F) {
 			lowercase = !lowercase;
@@ -116,15 +116,15 @@ void TextAsset::decodeHuffman() {
 	Common::BitStream8MSB stream(res, DisposeAfterUse::YES);
 	uint16 strLen = 0;
 	if (stream.getBit()) {
-		strLen = stream.getBits(15);
+		strLen = stream.getBits<15>();
 	} else {
-		strLen = stream.getBits(7);
+		strLen = stream.getBits<7>();
 	}
 	uint32 mask = 0;
 	uint32 symbol = 0;
 	char c;
 	for (uint16 i = 0; i < strLen; i++) {
-		mask = stream.peekBits(16);
+		mask = stream.peekBits<16>();
 
 		uint32 entry;
 		// Find the length index
@@ -139,16 +139,16 @@ void TextAsset::decodeHuffman() {
 		symbol = _huffman->getSymbol(entry);
 
 		if (symbol == 1) { // 7-bit ascii
-			c = stream.getBits(7);
+			c = stream.getBits<7>();
 			_decoded += c;
 		} else if (symbol == 2) { // Composite
 			if (stream.getBit()) { // TextID
-				ObjID embedId = stream.getBits(15);
+				ObjID embedId = stream.getBits<15>();
 			
 				TextAsset embedded(_engine, embedId, _sourceObj, _targetObj, _container, _isOld, _huffman);
 				_decoded += *embedded.decode();
 			} else { //Composite obj string
-				ObjID embedId = stream.getBits(8);
+				ObjID embedId = stream.getBits<8>();
 				_decoded += getNoun(embedId);
 			}
 		} else { // Plain ascii
diff --git a/image/codecs/indeo/get_bits.h b/image/codecs/indeo/get_bits.h
index 3c37f39b96c..b8162f41c56 100644
--- a/image/codecs/indeo/get_bits.h
+++ b/image/codecs/indeo/get_bits.h
@@ -50,13 +50,13 @@ public:
 	 *                  read the longest vlc code
 	 *                  = (max_vlc_length + bits - 1) / bits
 	 */
-	template <int maxDepth>
-	int getVLC2(int16 (*table)[2], int bits) {
+	template <int maxDepth, int bits>
+	int getVLC2(int16 (*table)[2]) {
 		int code;
 		int n, nbBits;
 		unsigned int index;
 
-		index = peekBits(bits);
+		index = peekBits<bits>();
 		code  = table[index][0];
 		n     = table[index][1];
 
diff --git a/image/codecs/indeo/indeo.cpp b/image/codecs/indeo/indeo.cpp
index 2988d141fec..6dbafe0e0b5 100644
--- a/image/codecs/indeo/indeo.cpp
+++ b/image/codecs/indeo/indeo.cpp
@@ -140,17 +140,17 @@ int IVIHuffTab::decodeHuffDesc(IVI45DecContext *ctx, int descCoded, int whichTab
 		return 0;
 	}
 
-	_tabSel = ctx->_gb->getBits(3);
+	_tabSel = ctx->_gb->getBits<3>();
 	if (_tabSel == 7) {
 		// custom huffman table (explicitly encoded)
-		newHuff._numRows = ctx->_gb->getBits(4);
+		newHuff._numRows = ctx->_gb->getBits<4>();
 		if (!newHuff._numRows) {
 			warning("Empty custom Huffman table!");
 			return -1;
 		}
 
 		for (int i = 0; i < newHuff._numRows; i++)
-			newHuff._xBits[i] = ctx->_gb->getBits(4);
+			newHuff._xBits[i] = ctx->_gb->getBits<4>();
 
 		// Have we got the same custom table? Rebuild if not.
 		if (newHuff.huffDescCompare(&_custDesc) || !_custTab._table) {
@@ -601,14 +601,14 @@ int IndeoDecoderBase::decodeIndeoFrame() {
 		int left;
 
 		// skip version string
-		while (_ctx._gb->getBits(8)) {
+		while (_ctx._gb->getBits<8>()) {
 			if (_ctx._gb->getBitsLeft() < 8)
 				return -1;
 		}
 		left = _ctx._gb->pos() & 0x18;
 		_ctx._gb->skip(64 - left);
 		if (_ctx._gb->getBitsLeft() > 18 &&
-			_ctx._gb->peekBits(21) == 0xBFFF8) { // syncheader + inter _type
+			_ctx._gb->peekBits<21>() == 0xBFFF8) { // syncheader + inter _type
 			error("Indeo decoder: Mode not currently implemented in ScummVM");
 		}
 	}
@@ -1048,9 +1048,9 @@ int IndeoDecoderBase::decodeTileDataSize(GetBits *gb) {
 	int len = 0;
 
 	if (gb->getBit()) {
-		len = gb->getBits(8);
+		len = gb->getBits<8>();
 		if (len == 255)
-			len = gb->getBits(24);
+			len = gb->getBits<24>();
 	}
 
 	// align the bitstream reader on the byte boundary
@@ -1266,15 +1266,15 @@ int IndeoDecoderBase::decodeCodedBlocks(GetBits *gb, IVIBandDesc *band,
 	// zero column flags
 	memset(colFlags, 0, sizeof(colFlags));
 	while (scanPos <= numCoeffs) {
-		sym = gb->getVLC2<1>(band->_blkVlc._tab->_table, IVI_VLC_BITS);
+		sym = gb->getVLC2<1, IVI_VLC_BITS>(band->_blkVlc._tab->_table);
 		if (sym == rvmap->_eobSym)
 			break; // End of block
 
 		// Escape - run/val explicitly coded using 3 vlc codes
 		if (sym == rvmap->_escSym) {
-			run = gb->getVLC2<1>(band->_blkVlc._tab->_table, IVI_VLC_BITS) + 1;
-			lo = gb->getVLC2<1>(band->_blkVlc._tab->_table, IVI_VLC_BITS);
-			hi = gb->getVLC2<1>(band->_blkVlc._tab->_table, IVI_VLC_BITS);
+			run = gb->getVLC2<1, IVI_VLC_BITS>(band->_blkVlc._tab->_table) + 1;
+			lo = gb->getVLC2<1, IVI_VLC_BITS>(band->_blkVlc._tab->_table);
+			hi = gb->getVLC2<1, IVI_VLC_BITS>(band->_blkVlc._tab->_table);
 			// merge them and convert into signed val
 			val = IVI_TOSIGNED((hi << 6) | lo);
 		} else {
diff --git a/image/codecs/indeo4.cpp b/image/codecs/indeo4.cpp
index 1f6fbe87014..d8b4ba714d6 100644
--- a/image/codecs/indeo4.cpp
+++ b/image/codecs/indeo4.cpp
@@ -59,7 +59,7 @@ bool Indeo4Decoder::isIndeo4(Common::SeekableReadStream &stream) {
 
 	// Validate the first 18-bit word has the correct identifier
 	Indeo::GetBits gb(buffer, 16 * 8);
-	bool isIndeo4 = gb.getBits(18) == 0x3FFF8;
+	bool isIndeo4 = gb.getBits<18>() == 0x3FFF8;
 
 	return isIndeo4;
 }
@@ -95,13 +95,13 @@ int Indeo4Decoder::decodePictureHeader() {
 	int pic_size_indx, i, p;
 	IVIPicConfig picConf;
 
-	if (_ctx._gb->getBits(18) != 0x3FFF8) {
+	if (_ctx._gb->getBits<18>() != 0x3FFF8) {
 		warning("Invalid picture start code!");
 		return -1;
 	}
 
 	_ctx._prevFrameType = _ctx._frameType;
-	_ctx._frameType = _ctx._gb->getBits(3);
+	_ctx._frameType = _ctx._gb->getBits<3>();
 	if (_ctx._frameType == 7) {
 		warning("Invalid frame type: %d", _ctx._frameType);
 		return -1;
@@ -124,7 +124,7 @@ int Indeo4Decoder::decodePictureHeader() {
 		return -1;
 	}
 
-	_ctx._dataSize = _ctx._gb->getBit() ? _ctx._gb->getBits(24) : 0;
+	_ctx._dataSize = _ctx._gb->getBit() ? _ctx._gb->getBits<24>() : 0;
 
 	// null frames don't contain anything else so we just return
 	if (_ctx._frameType >= IVI4_FRAMETYPE_NULL_FIRST) {
@@ -140,10 +140,10 @@ int Indeo4Decoder::decodePictureHeader() {
 		warning("Password-protected clip!");
 	}
 
-	pic_size_indx = _ctx._gb->getBits(3);
+	pic_size_indx = _ctx._gb->getBits<3>();
 	if (pic_size_indx == IVI4_PIC_SIZE_ESC) {
-		picConf._picHeight = _ctx._gb->getBits(16);
-		picConf._picWidth = _ctx._gb->getBits(16);
+		picConf._picHeight = _ctx._gb->getBits<16>();
+		picConf._picWidth = _ctx._gb->getBits<16>();
 	} else {
 		picConf._picHeight = _ivi4_common_pic_sizes[pic_size_indx * 2 + 1];
 		picConf._picWidth = _ivi4_common_pic_sizes[pic_size_indx * 2];
@@ -152,15 +152,15 @@ int Indeo4Decoder::decodePictureHeader() {
 	// Decode tile dimensions.
 	_ctx._usesTiling = _ctx._gb->getBit();
 	if (_ctx._usesTiling) {
-		picConf._tileHeight = scaleTileSize(picConf._picHeight, _ctx._gb->getBits(4));
-		picConf._tileWidth = scaleTileSize(picConf._picWidth, _ctx._gb->getBits(4));
+		picConf._tileHeight = scaleTileSize(picConf._picHeight, _ctx._gb->getBits<4>());
+		picConf._tileWidth = scaleTileSize(picConf._picWidth, _ctx._gb->getBits<4>());
 	} else {
 		picConf._tileHeight = picConf._picHeight;
 		picConf._tileWidth = picConf._picWidth;
 	}
 
 	// Decode chroma subsampling. We support only 4:4 aka YVU9.
-	if (_ctx._gb->getBits(2)) {
+	if (_ctx._gb->getBits<2>()) {
 		warning("Only YVU9 picture format is supported!");
 		return -1;
 	}
@@ -204,7 +204,7 @@ int Indeo4Decoder::decodePictureHeader() {
 		}
 	}
 
-	_ctx._frameNum = _ctx._gb->getBit() ? _ctx._gb->getBits(20) : 0;
+	_ctx._frameNum = _ctx._gb->getBit() ? _ctx._gb->getBits<20>() : 0;
 
 	// skip decTimeEst field if present
 	if (_ctx._gb->getBit())
@@ -215,17 +215,17 @@ int Indeo4Decoder::decodePictureHeader() {
 		_ctx._blkVlc.decodeHuffDesc(&_ctx, _ctx._gb->getBit(), IVI_BLK_HUFF))
 		return -1;
 
-	_ctx._rvmapSel = _ctx._gb->getBit() ? _ctx._gb->getBits(3) : 8;
+	_ctx._rvmapSel = _ctx._gb->getBit() ? _ctx._gb->getBits<3>() : 8;
 
 	_ctx._inImf = _ctx._gb->getBit();
 	_ctx._inQ = _ctx._gb->getBit();
 
-	_ctx._picGlobQuant = _ctx._gb->getBits(5);
+	_ctx._picGlobQuant = _ctx._gb->getBits<5>();
 
 	// TODO: ignore this parameter if unused
-	_ctx._unknown1 = _ctx._gb->getBit() ? _ctx._gb->getBits(3) : 0;
+	_ctx._unknown1 = _ctx._gb->getBit() ? _ctx._gb->getBits<3>() : 0;
 
-	_ctx._checksum = _ctx._gb->getBit() ? _ctx._gb->getBits(16) : 0;
+	_ctx._checksum = _ctx._gb->getBit() ? _ctx._gb->getBits<16>() : 0;
 
 	// skip picture header extension if any
 	while (_ctx._gb->getBit()) {
@@ -282,8 +282,8 @@ int Indeo4Decoder::decodeBandHeader(IVIBandDesc *band) {
 	int i;
 	int quantMat;
 
-	plane = _ctx._gb->getBits(2);
-	bandNum = _ctx._gb->getBits(4);
+	plane = _ctx._gb->getBits<2>();
+	bandNum = _ctx._gb->getBits<4>();
 	if (band->_plane != plane || band->_bandNum != bandNum) {
 		warning("Invalid band header sequence!");
 		return -1;
@@ -297,7 +297,7 @@ int Indeo4Decoder::decodeBandHeader(IVIBandDesc *band) {
 		if (_ctx._gb->getBit())
 			_ctx._gb->skip(16);
 
-		band->_isHalfpel = _ctx._gb->getBits(2);
+		band->_isHalfpel = _ctx._gb->getBits<2>();
 		if (band->_isHalfpel >= 2) {
 			warning("Invalid/unsupported mv resolution: %d!",
 				band->_isHalfpel);
@@ -308,9 +308,9 @@ int Indeo4Decoder::decodeBandHeader(IVIBandDesc *band) {
 
 		band->_checksumPresent = _ctx._gb->getBit();
 		if (band->_checksumPresent)
-			band->_checksum = _ctx._gb->getBits(16);
+			band->_checksum = _ctx._gb->getBits<16>();
 
-		indx = _ctx._gb->getBits(2);
+		indx = _ctx._gb->getBits<2>();
 		if (indx == 3) {
 			warning("Invalid block size!");
 			return -1;
@@ -321,10 +321,10 @@ int Indeo4Decoder::decodeBandHeader(IVIBandDesc *band) {
 		band->_inheritMv = _ctx._gb->getBit();
 		band->_inheritQDelta = _ctx._gb->getBit();
 
-		band->_globQuant = _ctx._gb->getBits(5);
+		band->_globQuant = _ctx._gb->getBits<5>();
 
 		if (!_ctx._gb->getBit() || _ctx._frameType == IVI4_FRAMETYPE_INTRA) {
-			transformId = _ctx._gb->getBits(5);
+			transformId = _ctx._gb->getBits<5>();
 			if ((uint)transformId >= FF_ARRAY_ELEMS(_transforms) ||
 				!_transforms[transformId]._invTrans) {
 				warning("Transform %d", transformId);
@@ -357,7 +357,7 @@ int Indeo4Decoder::decodeBandHeader(IVIBandDesc *band) {
 				return -1;
 			}
 
-			scanIndx = _ctx._gb->getBits(4);
+			scanIndx = _ctx._gb->getBits<4>();
 			if (scanIndx == 15) {
 				warning("Custom scan pattern encountered!");
 				return -1;
@@ -375,7 +375,7 @@ int Indeo4Decoder::decodeBandHeader(IVIBandDesc *band) {
 			band->_scan = _scan_index_to_tab[scanIndx];
 			band->_scanSize = band->_blkSize;
 
-			quantMat = _ctx._gb->getBits(5);
+			quantMat = _ctx._gb->getBits<5>();
 			if (quantMat == 31) {
 				warning("Custom quant matrix encountered!");
 				return -1;
@@ -413,12 +413,12 @@ int Indeo4Decoder::decodeBandHeader(IVIBandDesc *band) {
 				return -1;
 
 		// select appropriate rvmap table for this band
-		band->_rvmapSel = _ctx._gb->getBit() ? _ctx._gb->getBits(3) : 8;
+		band->_rvmapSel = _ctx._gb->getBit() ? _ctx._gb->getBits<3>() : 8;
 
 		// decode rvmap probability corrections if any
 		band->_numCorr = 0; // there is no corrections
 		if (_ctx._gb->getBit()) {
-			band->_numCorr = _ctx._gb->getBits(8); // get number of correction pairs
+			band->_numCorr = _ctx._gb->getBits<8>(); // get number of correction pairs
 			if (band->_numCorr > 61) {
 				warning("Too many corrections: %d",
 					band->_numCorr);
@@ -427,7 +427,7 @@ int Indeo4Decoder::decodeBandHeader(IVIBandDesc *band) {
 
 			// read correction pairs
 			for (i = 0; i < band->_numCorr * 2; i++)
-				band->_corr[i] = _ctx._gb->getBits(8);
+				band->_corr[i] = _ctx._gb->getBits<8>();
 		}
 	}
 
@@ -454,8 +454,8 @@ int Indeo4Decoder::decodeBandHeader(IVIBandDesc *band) {
 }
 
 int Indeo4Decoder::decodeMbInfo(IVIBandDesc *band, IVITile *tile) {
-	int x, y, mvX, mvY, mvDelta, offs, mbOffset, blksPerMb,
-		mvScale, mbTypeBits, s;
+	int x, y, mvX, mvY, mvDelta, offs, mbOffset,
+		mvScale, s;
 	IVIMbInfo *mb, *refMb;
 	int row_offset = band->_mbSize * band->_pitch;
 
@@ -463,9 +463,6 @@ int Indeo4Decoder::decodeMbInfo(IVIBandDesc *band, IVITile *tile) {
 	refMb = tile->_refMbs;
 	offs = tile->_yPos * band->_pitch + tile->_xPos;
 
-	blksPerMb = band->_mbSize != band->_blkSize ? 4 : 1;
-	mbTypeBits = _ctx._frameType == IVI4_FRAMETYPE_BIDIR ? 2 : 1;
-
 	// scale factor for motion vectors
 	mvScale = (_ctx._planes[0]._bands[0]._mbSize >> 3) - (band->_mbSize >> 3);
 	mvX = mvY = 0;
@@ -494,8 +491,7 @@ int Indeo4Decoder::decodeMbInfo(IVIBandDesc *band, IVITile *tile) {
 
 				mb->_qDelta = 0;
 				if (!band->_plane && !band->_bandNum && _ctx._inQ) {
-					mb->_qDelta = _ctx._gb->getVLC2<1>(_ctx._mbVlc._tab->_table,
-						IVI_VLC_BITS);
+					mb->_qDelta = _ctx._gb->getVLC2<1, IVI_VLC_BITS>(_ctx._mbVlc._tab->_table);
 					mb->_qDelta = IVI_TOSIGNED(mb->_qDelta);
 				}
 
@@ -521,19 +517,24 @@ int Indeo4Decoder::decodeMbInfo(IVIBandDesc *band, IVITile *tile) {
 				} else if (_ctx._frameType == IVI4_FRAMETYPE_INTRA ||
 					_ctx._frameType == IVI4_FRAMETYPE_INTRA1) {
 					mb->_type = 0; // mb_type is always INTRA for intra-frames
+				} else if (_ctx._frameType == IVI4_FRAMETYPE_BIDIR) {
+					mb->_type = _ctx._gb->getBits<2>();
 				} else {
-					mb->_type = _ctx._gb->getBits(mbTypeBits);
+					mb->_type = _ctx._gb->getBit();
 				}
 
-				mb->_cbp = _ctx._gb->getBits(blksPerMb);
+				if (band->_mbSize != band->_blkSize) {
+					mb->_cbp = _ctx._gb->getBits<4>();
+				} else {
+					mb->_cbp = _ctx._gb->getBit();
+				}
 
 				mb->_qDelta = 0;
 				if (band->_inheritQDelta) {
 					if (refMb) mb->_qDelta = refMb->_qDelta;
 				} else if (mb->_cbp || (!band->_plane && !band->_bandNum &&
 					_ctx._inQ)) {
-					mb->_qDelta = _ctx._gb->getVLC2<1>(_ctx._mbVlc._tab->_table,
-						IVI_VLC_BITS);
+					mb->_qDelta = _ctx._gb->getVLC2<1, IVI_VLC_BITS>(_ctx._mbVlc._tab->_table);
 					mb->_qDelta = IVI_TOSIGNED(mb->_qDelta);
 				}
 
@@ -553,22 +554,18 @@ int Indeo4Decoder::decodeMbInfo(IVIBandDesc *band, IVITile *tile) {
 						}
 					} else {
 						// decode motion vector deltas
-						mvDelta = _ctx._gb->getVLC2<1>(_ctx._mbVlc._tab->_table,
-							IVI_VLC_BITS);
+						mvDelta = _ctx._gb->getVLC2<1, IVI_VLC_BITS>(_ctx._mbVlc._tab->_table);
 						mvY += IVI_TOSIGNED(mvDelta);
-						mvDelta = _ctx._gb->getVLC2<1>(_ctx._mbVlc._tab->_table,
-							IVI_VLC_BITS);
+						mvDelta = _ctx._gb->getVLC2<1, IVI_VLC_BITS>(_ctx._mbVlc._tab->_table);
 						mvX += IVI_TOSIGNED(mvDelta);
 						mb->_mvX = mvX;
 						mb->_mvY = mvY;
 						if (mb->_type == 3) {
-							mvDelta = _ctx._gb->getVLC2<1>(
-								_ctx._mbVlc._tab->_table,
-								IVI_VLC_BITS);
+							mvDelta = _ctx._gb->getVLC2<1, IVI_VLC_BITS>(
+								_ctx._mbVlc._tab->_table);
 							mvY += IVI_TOSIGNED(mvDelta);
-							mvDelta = _ctx._gb->getVLC2<1>(
-								_ctx._mbVlc._tab->_table,
-								IVI_VLC_BITS);
+							mvDelta = _ctx._gb->getVLC2<1, IVI_VLC_BITS>(
+								_ctx._mbVlc._tab->_table);
 							mvX += IVI_TOSIGNED(mvDelta);
 							mb->_bMvX = -mvX;
 							mb->_bMvY = -mvY;
@@ -625,7 +622,7 @@ int Indeo4Decoder::decodeRLETransparency(VLC_TYPE (*table)[2]) {
 	int numPixelsToRead = codecAlignedWidth * _surface.h;
 	int numPixelsToSkip = 0;
 	while (numPixelsToRead > 0) {
-		int value = _ctx._gb->getVLC2<1>(table, IVI_VLC_BITS);
+		int value = _ctx._gb->getVLC2<1, IVI_VLC_BITS>(table);
 
 		if (value == -1) {
 			warning("Transparency VLC code read failed");
@@ -700,18 +697,18 @@ int Indeo4Decoder::decodeRLETransparency(VLC_TYPE (*table)[2]) {
 }
 
 int Indeo4Decoder::decodeTransparency() {
-	if (_ctx._gb->getBits(2) != 3 || _ctx._gb->getBits(3) != 0) {
+	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);
+	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));
 	}
 
@@ -719,7 +716,7 @@ int Indeo4Decoder::decodeTransparency() {
 
 	if (_ctx._gb->getBit()) { /* @350 */
 		/* @358 */
-		_ctx._transKeyColor = _surface.format.ARGBToColor(0, _ctx._gb->getBits(8), _ctx._gb->getBits(8), _ctx._gb->getBits(8));
+		_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 */
 	}
@@ -731,14 +728,14 @@ int Indeo4Decoder::decodeTransparency() {
 
 	IVIHuffDesc huffDesc;
 
-	const int numHuffRows = huffDesc._numRows = _ctx._gb->getBits(4);
+	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);
+		huffDesc._xBits[i] = _ctx._gb->getBits<4>();
 	}
 
 	/* @5E2 */
@@ -793,9 +790,9 @@ int Indeo4Decoder::decodeTransparency() {
 		const bool hasDataSize = _ctx._gb->getBit();
 		if (hasDataSize) { /* @81A */
 			/* @822 */
-			int expectedSize = _ctx._gb->getBits(8);
+			int expectedSize = _ctx._gb->getBits<8>();
 			if (expectedSize == 0xFF) {
-				expectedSize = _ctx._gb->getBits(24);
+				expectedSize = _ctx._gb->getBits<24>();
 			}
 
 			expectedSize -= ((_ctx._gb->pos() + 7) / 8) - startByte;
@@ -829,13 +826,13 @@ int Indeo4Decoder::scaleTileSize(int defSize, int sizeFactor) {
 int Indeo4Decoder::decodePlaneSubdivision() {
 	int i;
 
-	switch (_ctx._gb->getBits(2)) {
+	switch (_ctx._gb->getBits<2>()) {
 	case 3:
 		return 1;
 
 	case 2:
 		for (i = 0; i < 4; i++)
-			if (_ctx._gb->getBits(2) != 3)
+			if (_ctx._gb->getBits<2>() != 3)
 				return 0;
 		return 4;
 
diff --git a/image/codecs/indeo5.cpp b/image/codecs/indeo5.cpp
index e8989e43b14..ab45cd9d041 100644
--- a/image/codecs/indeo5.cpp
+++ b/image/codecs/indeo5.cpp
@@ -67,7 +67,7 @@ bool Indeo5Decoder::isIndeo5(Common::SeekableReadStream &stream) {
 
 	// Validate the first 5-bit word has the correct identifier
 	Indeo::GetBits gb(buffer, 16 * 8);
-	bool isIndeo5 = gb.getBits(5) == 0x1F;
+	bool isIndeo5 = gb.getBits<5>() == 0x1F;
 
 	return isIndeo5;
 }
@@ -103,19 +103,19 @@ int Indeo5Decoder::decodePictureHeader() {
 	IVIPicConfig picConf;
 	int ret;
 
-	if (_ctx._gb->getBits(5) != 0x1F) {
+	if (_ctx._gb->getBits<5>() != 0x1F) {
 		warning("Invalid picture start code!");
 		return -1;
 	}
 
 	_ctx._prevFrameType = _ctx._frameType;
-	_ctx._frameType = _ctx._gb->getBits(3);
+	_ctx._frameType = _ctx._gb->getBits<3>();
 	if (_ctx._frameType >= 5) {
 		warning("Invalid frame type: %d", _ctx._frameType);
 		return -1;
 	}
 
-	_ctx._frameNum = _ctx._gb->getBits(8);
+	_ctx._frameNum = _ctx._gb->getBits<8>();
 
 	if (_ctx._frameType == FRAMETYPE_INTRA) {
 		if ((ret = decode_gop_header()) < 0) {
@@ -133,11 +133,11 @@ int Indeo5Decoder::decodePictureHeader() {
 	}
 
 	if (_ctx._frameType != FRAMETYPE_NULL) {
-		_ctx._frameFlags = _ctx._gb->getBits(8);
+		_ctx._frameFlags = _ctx._gb->getBits<8>();
 
-		_ctx._picHdrSize = (_ctx._frameFlags & 1) ? _ctx._gb->getBits(24) : 0;
+		_ctx._picHdrSize = (_ctx._frameFlags & 1) ? _ctx._gb->getBits<24>() : 0;
 
-		_ctx._checksum = (_ctx._frameFlags & 0x10) ? _ctx._gb->getBits(16) : 0;
+		_ctx._checksum = (_ctx._frameFlags & 0x10) ? _ctx._gb->getBits<16>() : 0;
 
 		// skip unknown extension if any
 		if (_ctx._frameFlags & 0x20)
@@ -205,14 +205,14 @@ int Indeo5Decoder::decodeBandHeader(IVIBandDesc *band) {
 	int i, ret;
 	uint8 bandFlags;
 
-	bandFlags = _ctx._gb->getBits(8);
+	bandFlags = _ctx._gb->getBits<8>();
 
 	if (bandFlags & 1) {
 		band->_isEmpty = true;
 		return 0;
 	}
 
-	band->_dataSize = (_ctx._frameFlags & 0x80) ? _ctx._gb->getBits(24) : 0;
+	band->_dataSize = (_ctx._frameFlags & 0x80) ? _ctx._gb->getBits<24>() : 0;
 
 	band->_inheritMv = (bandFlags & 2) != 0;
 	band->_inheritQDelta = (bandFlags & 8) != 0;
@@ -223,7 +223,7 @@ int Indeo5Decoder::decodeBandHeader(IVIBandDesc *band) {
 	// decode rvmap probability corrections if any
 	band->_numCorr = 0; // there are no corrections
 	if (bandFlags & 0x10) {
-		band->_numCorr = _ctx._gb->getBits(8); // get number of correction pairs
+		band->_numCorr = _ctx._gb->getBits<8>(); // get number of correction pairs
 		if (band->_numCorr > 61) {
 			warning("Too many corrections: %d", band->_numCorr);
 			return -1;
@@ -231,11 +231,11 @@ int Indeo5Decoder::decodeBandHeader(IVIBandDesc *band) {
 
 		// read correction pairs
 		for (i = 0; i < band->_numCorr * 2; i++)
-			band->_corr[i] = _ctx._gb->getBits(8);
+			band->_corr[i] = _ctx._gb->getBits<8>();
 	}
 
 	// select appropriate rvmap table for this band
-	band->_rvmapSel = (bandFlags & 0x40) ? _ctx._gb->getBits(3) : 8;
+	band->_rvmapSel = (bandFlags & 0x40) ? _ctx._gb->getBits<3>() : 8;
 
 	// decode block huffman codebook
 	ret = band->_blkVlc.decodeHuffDesc(&_ctx, bandFlags & 0x80, IVI_BLK_HUFF);
@@ -244,9 +244,9 @@ int Indeo5Decoder::decodeBandHeader(IVIBandDesc *band) {
 
 	band->_checksumPresent = _ctx._gb->getBit();
 	if (band->_checksumPresent)
-		band->_checksum = _ctx._gb->getBits(16);
+		band->_checksum = _ctx._gb->getBits<16>();
 
-	band->_globQuant = _ctx._gb->getBits(5);
+	band->_globQuant = _ctx._gb->getBits<5>();
 
 	// skip unknown extension if any
 	if (bandFlags & 0x20) { // XXX: untested
@@ -260,7 +260,7 @@ int Indeo5Decoder::decodeBandHeader(IVIBandDesc *band) {
 }
 
 int Indeo5Decoder::decodeMbInfo(IVIBandDesc *band, IVITile *tile) {
-	int x, y, mvX, mvY, mvDelta, offs, mbOffset, mvScale, blksPerMb, s;
+	int x, y, mvX, mvY, mvDelta, offs, mbOffset, mvScale, s;
 	IVIMbInfo *mb, *refMb;
 	int rowOffset = band->_mbSize * band->_pitch;
 
@@ -300,7 +300,7 @@ int Indeo5Decoder::decodeMbInfo(IVIBandDesc *band, IVITile *tile) {
 
 				mb->_qDelta = 0;
 				if (!band->_plane && !band->_bandNum && (_ctx._frameFlags & 8)) {
-					mb->_qDelta = _ctx._gb->getVLC2<1>(_ctx._mbVlc._tab->_table, IVI_VLC_BITS);
+					mb->_qDelta = _ctx._gb->getVLC2<1, IVI_VLC_BITS>(_ctx._mbVlc._tab->_table);
 					mb->_qDelta = IVI_TOSIGNED(mb->_qDelta);
 				}
 
@@ -324,8 +324,11 @@ int Indeo5Decoder::decodeMbInfo(IVIBandDesc *band, IVITile *tile) {
 					mb->_type = _ctx._gb->getBit();
 				}
 
-				blksPerMb = band->_mbSize != band->_blkSize ? 4 : 1;
-				mb->_cbp = _ctx._gb->getBits(blksPerMb);
+				if (band->_mbSize != band->_blkSize) {
+					mb->_cbp = _ctx._gb->getBits<4>();
+				} else {
+					mb->_cbp = _ctx._gb->getBit();
+				}
 
 				mb->_qDelta = 0;
 				if (band->_qdeltaPresent) {
@@ -333,7 +336,7 @@ int Indeo5Decoder::decodeMbInfo(IVIBandDesc *band, IVITile *tile) {
 						if (refMb) mb->_qDelta = refMb->_qDelta;
 					} else if (mb->_cbp || (!band->_plane && !band->_bandNum &&
 						(_ctx._frameFlags & 8))) {
-						mb->_qDelta = _ctx._gb->getVLC2<1>(_ctx._mbVlc._tab->_table, IVI_VLC_BITS);
+						mb->_qDelta = _ctx._gb->getVLC2<1, IVI_VLC_BITS>(_ctx._mbVlc._tab->_table);
 						mb->_qDelta = IVI_TOSIGNED(mb->_qDelta);
 					}
 				}
@@ -352,9 +355,9 @@ int Indeo5Decoder::decodeMbInfo(IVIBandDesc *band, IVITile *tile) {
 						}
 					} else {
 						// decode motion vector deltas
-						mvDelta = _ctx._gb->getVLC2<1>(_ctx._mbVlc._tab->_table, IVI_VLC_BITS);
+						mvDelta = _ctx._gb->getVLC2<1, IVI_VLC_BITS>(_ctx._mbVlc._tab->_table);
 						mvY += IVI_TOSIGNED(mvDelta);
-						mvDelta = _ctx._gb->getVLC2<1>(_ctx._mbVlc._tab->_table, IVI_VLC_BITS);
+						mvDelta = _ctx._gb->getVLC2<1, IVI_VLC_BITS>(_ctx._mbVlc._tab->_table);
 						mvX += IVI_TOSIGNED(mvDelta);
 						mb->_mvX = mvX;
 						mb->_mvY = mvY;
@@ -392,14 +395,14 @@ int Indeo5Decoder::decode_gop_header() {
 	IVIBandDesc *band, *band1, *band2;
 	IVIPicConfig picConf;
 
-	_ctx._gopFlags = _ctx._gb->getBits(8);
+	_ctx._gopFlags = _ctx._gb->getBits<8>();
 
-	_ctx._gopHdrSize = (_ctx._gopFlags & 1) ? _ctx._gb->getBits(16) : 0;
+	_ctx._gopHdrSize = (_ctx._gopFlags & 1) ? _ctx._gb->getBits<16>() : 0;
 
 	if (_ctx._gopFlags & IVI5_IS_PROTECTED)
-		_ctx._lockWord = _ctx._gb->getBits(32);
+		_ctx._lockWord = _ctx._gb->getBits<32>();
 
-	tileSize = (_ctx._gopFlags & 0x40) ? 64 << _ctx._gb->getBits(2) : 0;
+	tileSize = (_ctx._gopFlags & 0x40) ? 64 << _ctx._gb->getBits<2>() : 0;
 	if (tileSize > 256) {
 		warning("Invalid tile size: %d", tileSize);
 		return -1;
@@ -407,7 +410,7 @@ int Indeo5Decoder::decode_gop_header() {
 
 	// decode number of wavelet bands
 	// num_levels * 3 + 1
-	picConf._lumaBands = _ctx._gb->getBits(2) * 3 + 1;
+	picConf._lumaBands = _ctx._gb->getBits<2>() * 3 + 1;
 	picConf._chromaBands = _ctx._gb->getBit() * 3 + 1;
 	isScalable = picConf._lumaBands != 1 || picConf._chromaBands != 1;
 	if (isScalable && (picConf._lumaBands != 4 || picConf._chromaBands != 1)) {
@@ -416,10 +419,10 @@ int Indeo5Decoder::decode_gop_header() {
 		return -1;
 	}
 
-	picSizeIndx = _ctx._gb->getBits(4);
+	picSizeIndx = _ctx._gb->getBits<4>();
 	if (picSizeIndx == IVI5_PIC_SIZE_ESC) {
-		picConf._picHeight = _ctx._gb->getBits(13);
-		picConf._picWidth = _ctx._gb->getBits(13);
+		picConf._picHeight = _ctx._gb->getBits<13>();
+		picConf._picWidth = _ctx._gb->getBits<13>();
 	} else {
 		picConf._picHeight = _commonPicSizes[picSizeIndx * 2 + 1] << 2;
 		picConf._picWidth = _commonPicSizes[picSizeIndx * 2] << 2;
@@ -550,7 +553,7 @@ int Indeo5Decoder::decode_gop_header() {
 				band->_interScale = _scaleQuant4x4Inter;
 			}
 
-			if (_ctx._gb->getBits(2)) {
+			if (_ctx._gb->getBits<2>()) {
 				warning("End marker missing!");
 				return -1;
 			}
@@ -589,7 +592,7 @@ int Indeo5Decoder::decode_gop_header() {
 	}
 
 	if (_ctx._gopFlags & 8) {
-		if (_ctx._gb->getBits(3)) {
+		if (_ctx._gb->getBits<3>()) {
 			warning("Alignment bits are not zero!");
 			return -1;
 		}
@@ -605,7 +608,7 @@ int Indeo5Decoder::decode_gop_header() {
 	// skip GOP extension if any
 	if (_ctx._gb->getBit()) {
 		do {
-			i = _ctx._gb->getBits(16);
+			i = _ctx._gb->getBits<16>();
 		} while (i & 0x8000);
 	}
 
@@ -618,7 +621,7 @@ int Indeo5Decoder::skip_hdr_extension() {
 	int i, len;
 
 	do {
-		len = _ctx._gb->getBits(8);
+		len = _ctx._gb->getBits<8>();
 		if (_ctx._gb->eos())
 			return -1;
 		for (i = 0; i < len; i++)
diff --git a/image/codecs/jyv1.cpp b/image/codecs/jyv1.cpp
index b7fb7fd2fe7..7e4e17470ff 100644
--- a/image/codecs/jyv1.cpp
+++ b/image/codecs/jyv1.cpp
@@ -91,7 +91,7 @@ const Graphics::Surface *JYV1Decoder::decodeFrame(Common::SeekableReadStream &st
 		Common::BitStreamMemory8MSB cmdBitStream(cmdMemStream);
 		int total = 0;
 		while (!cmdBitStream.eos()) {
-			uint32 idx = cmdBitStream.getBits(4);
+			uint32 idx = cmdBitStream.getBits<4>();
 			total += BASE_LEN[idx];
 			if (idx != 0 && idx != 8) {
 			   total += cmdBitStream.getBits(FINE_LEN_BITS[idx]);
@@ -117,7 +117,7 @@ const Graphics::Surface *JYV1Decoder::decodeFrame(Common::SeekableReadStream &st
 		Common::BitStreamMemory8MSB cmdBitStream(cmdMemStream);
 		bool skipping = true;
 		while (cmdBitStream.size() - cmdBitStream.pos() >= 4 && y < _height) {
-			uint32 idx = cmdBitStream.getBits(4);
+			uint32 idx = cmdBitStream.getBits<4>();
 			uint32 blocksize = BASE_LEN[idx];
 			if (idx != 0 && idx != 8) {
 			   blocksize += cmdBitStream.getBits(FINE_LEN_BITS[idx]);
diff --git a/image/codecs/svq1.cpp b/image/codecs/svq1.cpp
index 247ab5ed272..c02c5f22e09 100644
--- a/image/codecs/svq1.cpp
+++ b/image/codecs/svq1.cpp
@@ -95,7 +95,7 @@ const Graphics::Surface *SVQ1Decoder::decodeFrame(Common::SeekableReadStream &st
 
 	Common::BitStream32BEMSB frameData(stream);
 
-	uint32 frameCode = frameData.getBits(22);
+	uint32 frameCode = frameData.getBits<22>();
 	debug(1, " frameCode: %d", frameCode);
 
 	if ((frameCode & ~0x70) || !(frameCode & 0x60)) { // Invalid
@@ -103,23 +103,23 @@ const Graphics::Surface *SVQ1Decoder::decodeFrame(Common::SeekableReadStream &st
 		return _surface;
 	}
 
-	byte temporalReference = frameData.getBits(8);
+	byte temporalReference = frameData.getBits<8>();
 	debug(1, " temporalReference: %d", temporalReference);
 	static const char *const types[4] = { "I (Key)", "P (Delta from Previous)", "B (Delta from Next)", "Invalid" };
-	byte frameType = frameData.getBits(2);
+	byte frameType = frameData.getBits<2>();
 	debug(1, " frameType: %d = %s Frame", frameType, types[frameType]);
 
 	if (frameType == 0) { // I Frame
 		// TODO: Validate checksum if present
 		if (frameCode == 0x50 || frameCode == 0x60) {
-			uint32 checksum = frameData.getBits(16);
+			uint32 checksum = frameData.getBits<16>();
 			debug(1, " checksum:0x%02x", checksum);
 			// We're currently just ignoring the checksum
 		}
 
 		if ((frameCode ^ 0x10) >= 0x50) {
 			// Skip embedded string
-			byte stringLen = frameData.getBits(8);
+			byte stringLen = frameData.getBits<8>();
 			for (uint16 i = 0; i < stringLen-1; i++)
 				frameData.skip(8);
 		}
@@ -136,12 +136,12 @@ const Graphics::Surface *SVQ1Decoder::decodeFrame(Common::SeekableReadStream &st
 			{ 320, 240 }  // 6
 		};
 
-		byte frameSizeCode = frameData.getBits(3);
+		byte frameSizeCode = frameData.getBits<3>();
 		debug(1, " frameSizeCode: %d", frameSizeCode);
 
 		if (frameSizeCode == 7) {
-			_frameWidth = frameData.getBits(12);
-			_frameHeight = frameData.getBits(12);
+			_frameWidth = frameData.getBits<12>();
+			_frameHeight = frameData.getBits<12>();
 		} else {
 			_frameWidth = standardFrameSizes[frameSizeCode].w;
 			_frameHeight = standardFrameSizes[frameSizeCode].h;
@@ -164,7 +164,7 @@ const Graphics::Surface *SVQ1Decoder::decodeFrame(Common::SeekableReadStream &st
 		debug(1, " usePacketChecksum: %d", usePacketChecksum);
 		bool componentChecksumsAfterImageData = frameData.getBit() != 0;
 		debug(1, " componentChecksumsAfterImageData: %d", componentChecksumsAfterImageData);
-		byte unk4 = frameData.getBits(2);
+		byte unk4 = frameData.getBits<2>();
 		debug(1, " unk4: %d", unk4);
 		if (unk4 != 0)
 			warning("Invalid Frame Header in SVQ1 Frame Decode");
diff --git a/video/bink_decoder.cpp b/video/bink_decoder.cpp
index 8242200f0d3..2d0f3429dc0 100644
--- a/video/bink_decoder.cpp
+++ b/video/bink_decoder.cpp
@@ -537,15 +537,15 @@ void BinkDecoder::BinkVideoTrack::decodePlane(VideoFrame &video, int planeIdx, b
 	}
 
 	for (ctx.blockY = 0; ctx.blockY < blockHeight; ctx.blockY++) {
-		readBlockTypes  (video, _bundles[kSourceBlockTypes]);
-		readBlockTypes  (video, _bundles[kSourceSubBlockTypes]);
-		readColors      (video, _bundles[kSourceColors]);
-		readPatterns    (video, _bundles[kSourcePattern]);
-		readMotionValues(video, _bundles[kSourceXOff]);
-		readMotionValues(video, _bundles[kSourceYOff]);
-		readDCS         (video, _bundles[kSourceIntraDC], kDCStartBits, false);
-		readDCS         (video, _bundles[kSourceInterDC], kDCStartBits, true);
-		readRuns        (video, _bundles[kSourceRun]);
+		readBlockTypes              (video, _bundles[kSourceBlockTypes]);
+		readBlockTypes              (video, _bundles[kSourceSubBlockTypes]);
+		readColors                  (video, _bundles[kSourceColors]);
+		readPatterns                (video, _bundles[kSourcePattern]);
+		readMotionValues            (video, _bundles[kSourceXOff]);
+		readMotionValues            (video, _bundles[kSourceYOff]);
+		readDCS<kDCStartBits, false>(video, _bundles[kSourceIntraDC]);
+		readDCS<kDCStartBits, true> (video, _bundles[kSourceInterDC]);
+		readRuns                    (video, _bundles[kSourceRun]);
 
 		ctx.dest = ctx.destStart + 8 * ctx.blockY * ctx.pitch;
 		ctx.prev = ctx.prevStart + 8 * ctx.blockY * ctx.pitch;
@@ -621,7 +621,7 @@ void BinkDecoder::BinkVideoTrack::readBundle(VideoFrame &video, Source source) {
 }
 
 void BinkDecoder::BinkVideoTrack::readHuffman(VideoFrame &video, Huffman &huffman) {
-	huffman.index = video.bits->getBits(4);
+	huffman.index = video.bits->getBits<4>();
 
 	if (huffman.index == 0) {
 		// The first tree always gives raw nibbles
@@ -637,9 +637,9 @@ void BinkDecoder::BinkVideoTrack::readHuffman(VideoFrame &video, Huffman &huffma
 		// Symbol selection
 		memset(hasSymbol, 0, 16);
 
-		uint8 length = video.bits->getBits(3);
+		uint8 length = video.bits->getBits<3>();
 		for (int i = 0; i <= length; i++) {
-			huffman.symbols[i] = video.bits->getBits(4);
+			huffman.symbols[i] = video.bits->getBits<4>();
 			hasSymbol[huffman.symbols[i]] = 1;
 		}
 
@@ -655,7 +655,7 @@ void BinkDecoder::BinkVideoTrack::readHuffman(VideoFrame &video, Huffman &huffma
 	byte tmp1[16], tmp2[16];
 	byte *in = tmp1, *out = tmp2;
 
-	uint8 depth = video.bits->getBits(2);
+	uint8 depth = video.bits->getBits<2>();
 
 	for (int i = 0; i < 16; i++)
 		in[i] = i;
@@ -779,7 +779,7 @@ void BinkDecoder::BinkVideoTrack::blockScaledSkip(DecodeContext &ctx) {
 }
 
 void BinkDecoder::BinkVideoTrack::blockScaledRun(DecodeContext &ctx) {
-	const uint8 *scan = binkPatterns[ctx.video->bits->getBits(4)];
+	const uint8 *scan = binkPatterns[ctx.video->bits->getBits<4>()];
 
 	int i = 0;
 	do {
@@ -916,7 +916,7 @@ void BinkDecoder::BinkVideoTrack::blockMotion(DecodeContext &ctx) {
 }
 
 void BinkDecoder::BinkVideoTrack::blockRun(DecodeContext &ctx) {
-	const uint8 *scan = binkPatterns[ctx.video->bits->getBits(4)];
+	const uint8 *scan = binkPatterns[ctx.video->bits->getBits<4>()];
 
 	int i = 0;
 	do {
@@ -945,7 +945,7 @@ void BinkDecoder::BinkVideoTrack::blockRun(DecodeContext &ctx) {
 void BinkDecoder::BinkVideoTrack::blockResidue(DecodeContext &ctx) {
 	blockMotion(ctx);
 
-	byte v = ctx.video->bits->getBits(7);
+	byte v = ctx.video->bits->getBits<7>();
 
 	int16 block[64];
 	memset(block, 0, 64 * sizeof(int16));
@@ -1025,7 +1025,7 @@ void BinkDecoder::BinkVideoTrack::readRuns(VideoFrame &video, Bundle &bundle) {
 		error("Run value went out of bounds");
 
 	if (video.bits->getBit()) {
-		byte v = video.bits->getBits(4);
+		byte v = video.bits->getBits<4>();
 
 		memset(bundle.curDec, v, n);
 		bundle.curDec += n;
@@ -1045,7 +1045,7 @@ void BinkDecoder::BinkVideoTrack::readMotionValues(VideoFrame &video, Bundle &bu
 		error("Too many motion values");
 
 	if (video.bits->getBit()) {
-		byte v = video.bits->getBits(4);
+		byte v = video.bits->getBits<4>();
 
 		if (v) {
 			int sign = -(int)video.bits->getBit();
@@ -1082,7 +1082,7 @@ void BinkDecoder::BinkVideoTrack::readBlockTypes(VideoFrame &video, Bundle &bund
 		error("Too many block type values");
 
 	if (video.bits->getBit()) {
-		byte v = video.bits->getBits(4);
+		byte v = video.bits->getBits<4>();
 
 		memset(bundle.curDec, v, n);
 
@@ -1171,14 +1171,15 @@ void BinkDecoder::BinkVideoTrack::readColors(VideoFrame &video, Bundle &bundle)
 	}
 }
 
-void BinkDecoder::BinkVideoTrack::readDCS(VideoFrame &video, Bundle &bundle, int startBits, bool hasSign) {
+template<int startBits, bool hasSign>
+void BinkDecoder::BinkVideoTrack::readDCS(VideoFrame &video, Bundle &bundle) {
 	uint32 length = readBundleCount(video, bundle);
 	if (length == 0)
 		return;
 
 	int16 *dest = (int16 *) bundle.curDec;
 
-	int32 v = video.bits->getBits(startBits - (hasSign ? 1 : 0));
+	int32 v = video.bits->getBits<startBits - (hasSign ? 1 : 0)>();
 	if (v && hasSign) {
 		int sign = -(int)video.bits->getBit();
 		v = (v ^ sign) - sign;
@@ -1190,7 +1191,7 @@ void BinkDecoder::BinkVideoTrack::readDCS(VideoFrame &video, Bundle &bundle, int
 	for (uint32 i = 0; i < length; i += 8) {
 		uint32 length2 = MIN<uint32>(length - i, 8);
 
-		byte bSize = video.bits->getBits(4);
+		byte bSize = video.bits->getBits<4>();
 
 		if (bSize) {
 
@@ -1232,7 +1233,7 @@ void BinkDecoder::BinkVideoTrack::readDCTCoeffs(VideoFrame &video, int32 *block,
 	coefList[listEnd] = 2;  modeList[listEnd++] = 3;
 	coefList[listEnd] = 3;  modeList[listEnd++] = 3;
 
-	int bits = video.bits->getBits(4) - 1;
+	int bits = video.bits->getBits<4>() - 1;
 	for (int mask = bits >= 0 ? 1 << bits : 0; bits >= 0; mask >>= 1, bits--) {
 		int listPos = listStart;
 
@@ -1307,7 +1308,7 @@ void BinkDecoder::BinkVideoTrack::readDCTCoeffs(VideoFrame &video, int32 *block,
 		}
 	}
 
-	uint8 quantIdx = video.bits->getBits(4);
+	uint8 quantIdx = video.bits->getBits<4>();
 	const int32 *quant = isIntra ? binkIntraQuant[quantIdx] : binkInterQuant[quantIdx];
 	block[0] = (block[0] * quant[0]) >> 11;
 
@@ -1332,7 +1333,7 @@ void BinkDecoder::BinkVideoTrack::readResidue(VideoFrame &video, int16 *block, i
 	coefList[listEnd] = 44; modeList[listEnd++] = 0;
 	coefList[listEnd] =  0; modeList[listEnd++] = 2;
 
-	for (int mask = 1 << video.bits->getBits(3); mask; mask >>= 1) {
+	for (int mask = 1 << video.bits->getBits<3>(); mask; mask >>= 1) {
 
 		for (int i = 0; i < nzCoeffCount; i++) {
 			if (!video.bits->getBit())
@@ -1596,7 +1597,7 @@ void BinkDecoder::BinkAudioTrack::readAudioCoeffs(float *coeffs) {
 	float quant[25];
 
 	for (uint32 i = 0; i < _audioInfo->bandCount; i++) {
-		int value = _audioInfo->bits->getBits(8);
+		int value = _audioInfo->bits->getBits<8>();
 
 		//                              0.066399999 / log10(M_E)
 		quant[i] = exp(MIN(value, 95) * 0.15289164787221953823f) * _audioInfo->root;
@@ -1615,13 +1616,13 @@ void BinkDecoder::BinkAudioTrack::readAudioCoeffs(float *coeffs) {
 
 		uint32 j = 0;
 		if (_audioInfo->bits->getBit())
-			j = i + rleLengthTab[_audioInfo->bits->getBits(4)] * 8;
+			j = i + rleLengthTab[_audioInfo->bits->getBits<4>()] * 8;
 		else
 			j = i + 8;
 
 		j = MIN(j, _audioInfo->frameLen);
 
-		int width = _audioInfo->bits->getBits(4);
+		int width = _audioInfo->bits->getBits<4>();
 		if (width == 0) {
 
 			memset(coeffs + i, 0, (j - i) * sizeof(*coeffs));
@@ -1673,9 +1674,9 @@ void BinkDecoder::BinkAudioTrack::floatToInt16Interleave(int16 *dst, const float
 }
 
 float BinkDecoder::BinkAudioTrack::getFloat() {
-	int power = _audioInfo->bits->getBits(5);
+	int power = _audioInfo->bits->getBits<5>();
 
-	float f = ldexp((float)_audioInfo->bits->getBits(23), power - 23);
+	float f = ldexp((float)_audioInfo->bits->getBits<23>(), power - 23);
 
 	if (_audioInfo->bits->getBit())
 		f = -f;
diff --git a/video/bink_decoder.h b/video/bink_decoder.h
index f74287f666c..9b0693470d3 100644
--- a/video/bink_decoder.h
+++ b/video/bink_decoder.h
@@ -320,7 +320,8 @@ private:
 		void readBlockTypes  (VideoFrame &video, Bundle &bundle);
 		void readPatterns    (VideoFrame &video, Bundle &bundle);
 		void readColors      (VideoFrame &video, Bundle &bundle);
-		void readDCS         (VideoFrame &video, Bundle &bundle, int startBits, bool hasSign);
+		template<int startBits, bool hasSign>
+		void readDCS         (VideoFrame &video, Bundle &bundle);
 		void readDCTCoeffs   (VideoFrame &video, int32 *block, bool isIntra);
 		void readResidue     (VideoFrame &video, int16 *block, int masksCount);
 
diff --git a/video/psx_decoder.cpp b/video/psx_decoder.cpp
index 895cfcbd29a..4658f0821d8 100644
--- a/video/psx_decoder.cpp
+++ b/video/psx_decoder.cpp
@@ -389,8 +389,8 @@ void PSXStreamDecoder::PSXVideoTrack::decodeFrame(Common::BitStreamMemoryStream
 
 	bits.skip(16); // unknown
 	bits.skip(16); // 0x3800
-	uint16 scale = bits.getBits(16);
-	uint16 version = bits.getBits(16);
+	uint16 scale = bits.getBits<16>();
+	uint16 version = bits.getBits<16>();
 
 	if (version != 2 && version != 3)
 		error("Unknown PSX stream frame version");
@@ -506,7 +506,7 @@ void PSXStreamDecoder::PSXVideoTrack::readAC(Common::BitStreamMemory16LEMSB *bit
 
 		if (symbol == ESCAPE_CODE) {
 			// The escape code!
-			int zeroes = bits->getBits(6);
+			int zeroes = bits->getBits<6>();
 			count += zeroes + 1;
 			BLOCK_OVERFLOW_CHECK();
 			block += zeroes;
@@ -530,7 +530,7 @@ void PSXStreamDecoder::PSXVideoTrack::readAC(Common::BitStreamMemory16LEMSB *bit
 }
 
 int PSXStreamDecoder::PSXVideoTrack::readSignedCoefficient(Common::BitStreamMemory16LEMSB *bits) {
-	uint val = bits->getBits(10);
+	uint val = bits->getBits<10>();
 
 	// extend the sign
 	uint shift = 8 * sizeof(int) - 10;
diff --git a/video/smk_decoder.cpp b/video/smk_decoder.cpp
index bc6c506c990..e918f23d118 100644
--- a/video/smk_decoder.cpp
+++ b/video/smk_decoder.cpp
@@ -93,7 +93,7 @@ uint16 SmallHuffmanTree::decodeTree(uint32 prefix, int length) {
 		return 0;
 
 	if (!_bs.getBit()) { // Leaf
-		_tree[_treeSize] = _bs.getBits(8);
+		_tree[_treeSize] = _bs.getBits<8>();
 
 		if (length <= 8) {
 			for (int i = 0; i < 256; i += (1 << length)) {
@@ -126,7 +126,10 @@ uint16 SmallHuffmanTree::getCode(Common::BitStreamMemory8LSB &bs) {
 	if (_empty)
 		return 0;
 
-	byte peek = bs.peekBits(MIN<uint32>(bs.size() - bs.pos(), 8));
+	// 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.
+	byte peek = bs.peekBits<8>();
 	uint16 *p = &_tree[_prefixtree[peek]];
 	bs.skip(_prefixlength[peek]);
 
@@ -188,9 +191,9 @@ BigHuffmanTree::BigHuffmanTree(Common::BitStreamMemory8LSB &bs, int allocSize)
 	_loBytes = new SmallHuffmanTree(_bs);
 	_hiBytes = new SmallHuffmanTree(_bs);
 
-	_markers[0] = _bs.getBits(16);
-	_markers[1] = _bs.getBits(16);
-	_markers[2] = _bs.getBits(16);
+	_markers[0] = _bs.getBits<16>();
+	_markers[1] = _bs.getBits<16>();
+	_markers[2] = _bs.getBits<16>();
 
 	_last[0] = _last[1] = _last[2] = 0xffffffff;
 
@@ -263,7 +266,10 @@ uint32 BigHuffmanTree::decodeTree(uint32 prefix, int length) {
 }
 
 uint32 BigHuffmanTree::getCode(Common::BitStreamMemory8LSB &bs) {
-	byte peek = bs.peekBits(MIN<uint32>(bs.size() - bs.pos(), 8));
+	// 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.
+	byte peek = bs.peekBits<8>();
 	uint32 *p = &_tree[_prefixtree[peek]];
 	bs.skip(_prefixlength[peek]);
 
@@ -874,16 +880,16 @@ void SmackerDecoder::SmackerAudioTrack::queueCompressedBuffer(byte *buffer, uint
 
 	if (isStereo) {
 		if (is16Bits) {
-			bases[1] = SWAP_BYTES_16(audioBS.getBits(16));
+			bases[1] = SWAP_BYTES_16(audioBS.getBits<16>());
 		} else {
-			bases[1] = audioBS.getBits(8);
+			bases[1] = audioBS.getBits<8>();
 		}
 	}
 
 	if (is16Bits) {
-		bases[0] = SWAP_BYTES_16(audioBS.getBits(16));
+		bases[0] = SWAP_BYTES_16(audioBS.getBits<16>());
 	} else {
-		bases[0] = audioBS.getBits(8);
+		bases[0] = audioBS.getBits<8>();
 	}
 
 	// The bases are the first samples, too




More information about the Scummvm-git-logs mailing list