mirror of
https://github.com/libretro/scummvm.git
synced 2024-11-27 11:20:40 +00:00
VIDEO: Avoid 64-bit math in Smacker bitstreams
This commit is contained in:
parent
d3069f84e8
commit
9a71eb1a6d
@ -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;
|
||||
|
||||
/** @} */
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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; }
|
||||
|
Loading…
Reference in New Issue
Block a user