[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