diff options
-rw-r--r-- | common/bitstream.cpp | 217 | ||||
-rw-r--r-- | common/bitstream.h | 361 | ||||
-rw-r--r-- | common/module.mk | 1 | ||||
-rw-r--r-- | video/bink_decoder.cpp | 20 |
4 files changed, 256 insertions, 343 deletions
diff --git a/common/bitstream.cpp b/common/bitstream.cpp deleted file mode 100644 index b41ad237e0..0000000000 --- a/common/bitstream.cpp +++ /dev/null @@ -1,217 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -// Based on eos' BitStream implementation - -#include "common/bitstream.h" -#include "common/memstream.h" -#include "common/stream.h" -#include "common/textconsole.h" -#include "common/util.h" - -namespace Common { - -BitStream::BitStream() { -} - -BitStream::~BitStream() { -} - -void BitStream::skip(uint32 n) { - while (n-- > 0) - getBit(); -} - - -BitStreamBE::BitStreamBE(SeekableReadStream &stream, uint32 bitCount) : _value(0), _inValue(0) { - if ((bitCount % 8) != 0) - error("Big-endian bit stream size has to be divisible by 8"); - - // Read the number of bytes of the stream - - uint32 byteSize = bitCount / 8; - byte *data = (byte *)malloc(byteSize); - - if (stream.read(data, byteSize) != byteSize) { - free(data); - error("Bad BitStreamBE size"); - } - - _stream = new MemoryReadStream(data, byteSize, DisposeAfterUse::YES); -} - -BitStreamBE::BitStreamBE(const byte *data, uint32 bitCount) : _value(0), _inValue(0) { - if ((bitCount % 8) != 0) - error("Big-endian bit stream size has to be divisible by 8"); - - // Copy the number of bytes from the data array - - uint32 byteSize = bitCount / 8; - byte *dataN = (byte *)malloc(byteSize); - - memcpy(dataN, data, byteSize); - - _stream = new MemoryReadStream(dataN, byteSize, DisposeAfterUse::YES); -} - -BitStreamBE::~BitStreamBE() { - delete _stream; -} - -uint32 BitStreamBE::getBit() { - if (_inValue == 0) { - // Need to get new byte - - if (_stream->eos()) - error("End of bit stream reached"); - - _value = _stream->readByte(); - } - - // Get the current bit - int b = ((_value & 0x80) == 0) ? 0 : 1; - - // Shift to the next bit - _value <<= 1; - - // Increase the position within the current byte - _inValue = (_inValue + 1) % 8; - - return b; -} - -uint32 BitStreamBE::getBits(uint32 n) { - if (n > 32) - error("Too many bits requested to be read"); - - // Read the number of bits - uint32 v = 0; - while (n-- > 0) - v = (v << 1) | getBit(); - - return v; -} - -void BitStreamBE::addBit(uint32 &x, uint32 n) { - x = (x << 1) | getBit(); -} - -uint32 BitStreamBE::pos() const { - if (_stream->pos() == 0) - return 0; - - uint32 p = (_inValue == 0) ? _stream->pos() : (_stream->pos() - 1); - return p * 8 + _inValue; -} - -uint32 BitStreamBE::size() const { - return _stream->size() * 8; -} - - -BitStream32LE::BitStream32LE(SeekableReadStream &stream, uint32 bitCount) : _value(0), _inValue(0) { - if ((bitCount % 32) != 0) - error("32bit little-endian bit stream size has to be divisible by 32"); - - // Read the number of bytes of the stream - - uint32 byteSize = bitCount / 8; - byte *data = (byte *)malloc(byteSize); - - if (stream.read(data, byteSize) != byteSize) { - free(data); - error("Bad BitStream32LE size"); - } - - _stream = new MemoryReadStream(data, byteSize, DisposeAfterUse::YES); -} - -BitStream32LE::BitStream32LE(const byte *data, uint32 bitCount) : _value(0), _inValue(0) { - if ((bitCount % 32) != 0) - error("32bit little-endian bit stream size has to be divisible by 32"); - - // Copy the number of bytes from the data array - - uint32 byteSize = bitCount / 8; - byte *dataN = (byte *)malloc(byteSize); - - memcpy(dataN, data, byteSize); - - _stream = new MemoryReadStream(dataN, byteSize, DisposeAfterUse::YES); -} - -BitStream32LE::~BitStream32LE() { - delete _stream; -} - -uint32 BitStream32LE::getBit() { - if (_inValue == 0) { - // Need to get new 32bit value - - if (_stream->eos()) - error("End of bit stream reached"); - - _value = _stream->readUint32LE(); - } - - // Get the current bit - int b = ((_value & 1) == 0) ? 0 : 1; - - // Shift to the next bit - _value >>= 1; - - // Increase the position within the current byte - _inValue = (_inValue + 1) % 32; - - return b; -} - -uint32 BitStream32LE::getBits(uint32 n) { - if (n > 32) - error("Too many bits requested to be read"); - - // Read the number of bits - uint32 v = 0; - for (uint32 i = 0; i < n; i++) - v = (v >> 1) | (((uint32) getBit()) << 31); - - v >>= (32 - n); - return v; -} - -void BitStream32LE::addBit(uint32 &x, uint32 n) { - x = (x & ~(1 << n)) | (getBit() << n); -} - -uint32 BitStream32LE::pos() const { - if (_stream->pos() == 0) - return 0; - - uint32 p = ((_inValue == 0) ? _stream->pos() : (_stream->pos() - 1)) & 0xFFFFFFFC; - return p * 8 + _inValue; -} - -uint32 BitStream32LE::size() const { - return _stream->size() * 8; -} - -} // End of namespace Common diff --git a/common/bitstream.h b/common/bitstream.h index 7be0dccf45..34063dbfe1 100644 --- a/common/bitstream.h +++ b/common/bitstream.h @@ -26,148 +26,269 @@ #define COMMON_BITSTREAM_H #include "common/scummsys.h" +#include "common/textconsole.h" +#include "common/stream.h" namespace Common { -class SeekableReadStream; - -/** - * A bit stream, giving access to data one bit at a time. - * - * Used in engines: - * - scumm - */ +/** A bit stream. */ class BitStream { public: - BitStream(); - virtual ~BitStream(); + virtual ~BitStream() { + } - /** Read a bit from the bitstream. */ - virtual uint32 getBit() = 0; + /** Return the stream position in bits. */ + virtual uint32 pos() const = 0; - /** Read a number of bits, creating a multi-bit value. */ - virtual uint32 getBits(uint32 n) = 0; + /** Return the stream size in bits. */ + virtual uint32 size() const = 0; - /** Add more bits, creating a multi-bit value in stages. */ - virtual void addBit(uint32 &x, uint32 n) = 0; + /** Has the end of the stream been reached? */ + virtual bool eos() const = 0; - /** Skip a number of bits. */ - void skip(uint32 n); + /** Rewind the bit stream back to the start. */ + virtual void rewind() = 0; - /** Get the current position, in bits. */ - virtual uint32 pos() const = 0; - /** Return the number of bits in the stream. */ - virtual uint32 size() const = 0; -}; + /** Skip the specified amount of bits. */ + virtual void skip(uint32 n) = 0; -/** - * A big-endian bit stream. - * - * The input data is read one byte at a time. Their bits are handed out - * in the order of MSB to LSB. When all 8 bits of a byte have been consumed, - * another input data byte is read. - */ -class BitStreamBE : public BitStream { -public: - /** - * Create a big endian bit stream. - * - * Reads and copies bitCount bits from the provided stream. - * Ownership of the stream is not transferred. - */ - BitStreamBE(SeekableReadStream &stream, uint32 bitCount); - - /** - * Create a big endian bit stream. - * - * Reads and copies bitCount bits from the provided data. - * Ownership of the data is not transferred. - */ - BitStreamBE(const byte *data, uint32 bitCount); - - ~BitStreamBE(); - - uint32 getBit(); - - /** - * Read a number of bits, creating a multi-bit value. - * - * The bits are read one at a time, in the order MSB to LSB and - * or'd together to create a multi-bit value. - */ - uint32 getBits(uint32 n); - - /** - * Add more bits, creating a multi-bit value in stages. - * - * Shifts in n new bits into the value x, in the order of MSB to LSB. - */ - void addBit(uint32 &x, uint32 n); - - uint32 pos() const; - uint32 size() const; + /** Read a bit from the bit stream. */ + virtual uint32 getBit() = 0; -private: - SeekableReadStream *_stream; + /** Read a multi-bit value from the bit stream. */ + virtual uint32 getBits(uint8 n) = 0; + + /** Read a bit from the bit stream, without changing the stream's position. */ + virtual uint32 peekBit() = 0; + + /** Read a multi-bit value from the bit stream, without changing the stream's position. */ + virtual uint32 peekBits(uint8 n) = 0; + + /** Add a bit to the value x, making it an n-bit value. */ + virtual void addBit(uint32 &x, uint32 n) = 0; - byte _value; ///< Current byte. - uint8 _inValue; ///< Position within the current byte. +protected: + BitStream() { + } }; /** - * A little-endian bit stream, reading 32bit values at a time. + * A template implementing a bit stream for different data memory layouts. + * + * Such a bit stream reads valueBits-wide values from the data stream and + * gives * access to their bits, one at a time. * - * The input data is read one little-endian uint32 at a time. Their bits are - * handed out in the order of LSB to MSB. When all 8 bits of a byte have been - * consumed, another little-endian input data uint32 is read. + * For example, a bit stream with the layout parameters 32, true, false + * for valueBits, isLE and isMSB2LSB, reads 32bit little-endian values + * from the data stream and hands out the bits in the order of LSB to MSB. */ -class BitStream32LE : public BitStream { -public: - /** - * Create a little-endian bit stream. - * - * Reads and copies bitCount bits from the provided stream. - * Ownership of the stream is not transferred. - */ - BitStream32LE(SeekableReadStream &stream, uint32 bitCount); - - /** - * Create a little-endian bit stream. - * - * Reads and copies bitCount bits from the provided data. - * Ownership of the data is not transferred. - */ - BitStream32LE(const byte *data, uint32 bitCount); - - ~BitStream32LE(); - - uint32 getBit(); - - /** - * Read a number of bits, creating a multi-bit value. - * - * The bits are read one at a time, in the order LSB to MSB and - * or'd together to create a multi-bit value. - */ - uint32 getBits(uint32 n); - - /** - * Add more bits, creating a multi-bit value in stages. - * - * Shifts in n new bits into the value x, in the order of LSB to MSB. - */ - void addBit(uint32 &x, uint32 n); - - uint32 pos() const; - uint32 size() const; - +template<int valueBits, bool isLE, bool isMSB2LSB> +class BitStreamImpl : public BitStream { private: - SeekableReadStream *_stream; + SeekableReadStream *_stream; ///< The input stream. + bool _disposeAfterUse; ///< Should we delete the stream on destruction? + + uint32 _value; ///< Current value. + uint8 _inValue; ///< Position within the current value. + + /** Read a data value. */ + inline uint32 readData() { + if (isLE) { + if (valueBits == 8) + return _stream->readByte(); + if (valueBits == 16) + return _stream->readUint16LE(); + if (valueBits == 32) + return _stream->readUint32LE(); + } else { + if (valueBits == 8) + return _stream->readByte(); + if (valueBits == 16) + return _stream->readUint16BE(); + if (valueBits == 32) + return _stream->readUint32BE(); + } + + assert(false); + return 0; + } + + /** Read the next data value. */ + inline void readValue() { + if ((size() - pos()) < valueBits) + error("BitStreamImpl::readValue(): End of bit stream reached"); + + _value = readData(); + if (_stream->err() || _stream->eos()) + error("BitStreamImpl::readValue(): Read error"); + + // If we're reading the bits MSB first, we need to shift the value to that position + if (isMSB2LSB) + _value <<= 32 - valueBits; + } - uint32 _value; ///< Current 32bit value. - uint8 _inValue; ///< Position within the current 32bit value. +public: + /** Create a bit stream using this input data stream and optionally delete it on destruction. */ + BitStreamImpl(SeekableReadStream *stream, bool disposeAfterUse = false) : + _stream(stream), _disposeAfterUse(disposeAfterUse), _value(0), _inValue(0) { + + if ((valueBits != 8) && (valueBits != 16) && (valueBits != 32)) + error("BitStreamImpl: Invalid memory layout %d, %d, %d", valueBits, isLE, isMSB2LSB); + } + + /** Create a bit stream using this input data stream. */ + BitStreamImpl(SeekableReadStream &stream) : + _stream(&stream), _disposeAfterUse(false), _value(0), _inValue(0) { + + if ((valueBits != 8) && (valueBits != 16) && (valueBits != 32)) + error("BitStreamImpl: Invalid memory layout %d, %d, %d", valueBits, isLE, isMSB2LSB); + } + + ~BitStreamImpl() { + if (_disposeAfterUse) + delete _stream; + } + + /** Read a bit from the bit stream. */ + uint32 getBit() { + // Check if we need the next value + if (_inValue == 0) + readValue(); + + // Get the current bit + int b = 0; + if (isMSB2LSB) + b = ((_value & 0x80000000) == 0) ? 0 : 1; + else + b = ((_value & 1) == 0) ? 0 : 1; + + // Shift to the next bit + if (isMSB2LSB) + _value <<= 1; + else + _value >>= 1; + + // Increase the position within the current value + _inValue = (_inValue + 1) % valueBits; + + return b; + } + + /** Read a multi-bit value from the bit stream. */ + uint32 getBits(uint8 n) { + if (n > 32) + error("BitStreamImpl::getBits(): Too many bits requested to be read"); + + // Read the number of bits + uint32 v = 0; + + if (isMSB2LSB) { + while (n-- > 0) + v = (v << 1) | getBit(); + } else { + for (uint32 i = 0; i < n; i++) + v = (v >> 1) | (((uint32) getBit()) << 31); + + v >>= (32 - n); + } + + return v; + } + + uint32 peekBit() { + uint32 value = _value; + uint8 inValue = _inValue; + uint32 curPos = _stream->pos(); + + uint32 v = getBit(); + + _stream->seek(curPos); + _inValue = inValue; + _value = value; + + return v; + } + + uint32 peekBits(uint8 n) { + uint32 value = _value; + uint8 inValue = _inValue; + uint32 curPos = _stream->pos(); + + uint32 v = getBits(n); + + _stream->seek(curPos); + _inValue = inValue; + _value = value; + + return v; + } + + /** Add a bit to the value x, making it an n-bit value. */ + void addBit(uint32 &x, uint32 n) { + if (isMSB2LSB) + x = (x << 1) | getBit(); + else + x = (x & ~(1 << n)) | (getBit() << n); + } + + /** Rewind the bit stream back to the start. */ + void rewind() { + _stream->seek(0); + + _value = 0; + _inValue = 0; + } + + /** Skip the specified amount of bits. */ + void skip(uint32 n) { + while (n-- > 0) + getBit(); + } + + /** Return the stream position in bits. */ + uint32 pos() const { + if (_stream->pos() == 0) + return 0; + + uint32 p = (_inValue == 0) ? _stream->pos() : ((_stream->pos() - 1) & ~((uint32) ((valueBits >> 3) - 1))); + return p * 8 + _inValue; + } + + /** Return the stream size in bits. */ + uint32 size() const { + return (_stream->size() & ~((uint32) ((valueBits >> 3) - 1))) * 8; + } + + bool eos() const { + return _stream->eos() || (pos() >= size()); + } }; +// typedefs for various memory layouts. + +/** 8-bit data, MSB to LSB. */ +typedef BitStreamImpl<8, false, true > BitStream8MSB; +/** 8-bit data, LSB to MSB. */ +typedef BitStreamImpl<8, false, false> BitStream8LSB; + +/** 16-bit little-endian data, MSB to LSB. */ +typedef BitStreamImpl<16, true , true > BitStream16LEMSB; +/** 16-bit little-endian data, LSB to MSB. */ +typedef BitStreamImpl<16, true , false> BitStream16LELSB; +/** 16-bit big-endian data, MSB to LSB. */ +typedef BitStreamImpl<16, false, true > BitStream16BEMSB; +/** 16-bit big-endian data, LSB to MSB. */ +typedef BitStreamImpl<16, false, false> BitStream16BELSB; + +/** 32-bit little-endian data, MSB to LSB. */ +typedef BitStreamImpl<32, true , true > BitStream32LEMSB; +/** 32-bit little-endian data, LSB to MSB. */ +typedef BitStreamImpl<32, true , false> BitStream32LELSB; +/** 32-bit big-endian data, MSB to LSB. */ +typedef BitStreamImpl<32, false, true > BitStream32BEMSB; +/** 32-bit big-endian data, LSB to MSB. */ +typedef BitStreamImpl<32, false, false> BitStream32BELSB; + } // End of namespace Common #endif // COMMON_BITSTREAM_H diff --git a/common/module.mk b/common/module.mk index b55c11637a..7434df7052 100644 --- a/common/module.mk +++ b/common/module.mk @@ -38,7 +38,6 @@ MODULE_OBJS := \ ifdef USE_BINK MODULE_OBJS += \ - bitstream.o \ cosinetables.o \ dct.o \ fft.o \ diff --git a/video/bink_decoder.cpp b/video/bink_decoder.cpp index c02042f972..41cd591282 100644 --- a/video/bink_decoder.cpp +++ b/video/bink_decoder.cpp @@ -30,6 +30,7 @@ #include "common/textconsole.h" #include "common/math.h" #include "common/stream.h" +#include "common/substream.h" #include "common/file.h" #include "common/str.h" #include "common/bitstream.h" @@ -199,28 +200,37 @@ const Graphics::Surface *BinkDecoder::decodeNextFrame() { error("Audio packet too big for the frame"); if (audioPacketLength >= 4) { + uint32 audioPacketStart = _bink->pos(); + uint32 audioPacketEnd = _bink->pos() + audioPacketLength; + if (i == _audioTrack) { // Only play one audio track // Number of samples in bytes audio.sampleCount = _bink->readUint32LE() / (2 * audio.channels); - audio.bits = new Common::BitStream32LE(*_bink, (audioPacketLength - 4) * 8); + audio.bits = + new Common::BitStream32LELSB(new Common::SeekableSubReadStream(_bink, + audioPacketStart + 4, audioPacketEnd), true); audioPacket(audio); delete audio.bits; audio.bits = 0; + } - } else - // Skip the rest - _bink->skip(audioPacketLength); + _bink->seek(audioPacketEnd); frameSize -= audioPacketLength; } } - frame.bits = new Common::BitStream32LE(*_bink, frameSize * 8); + uint32 videoPacketStart = _bink->pos(); + uint32 videoPacketEnd = _bink->pos() + frameSize; + + frame.bits = + new Common::BitStream32LELSB(new Common::SeekableSubReadStream(_bink, + videoPacketStart, videoPacketEnd), true); videoPacket(frame); |