IMAGE: Beginning of Indeo 4 decoder, added GetBits class for reading bits

This commit is contained in:
Paul Gilbert 2016-09-05 13:34:33 -04:00
parent d3d0819b00
commit 73e7903186
6 changed files with 783 additions and 1 deletions

View File

@ -30,6 +30,7 @@
#include "image/codecs/cdtoons.h"
#include "image/codecs/cinepak.h"
#include "image/codecs/indeo3.h"
#include "image/codecs/indeo4.h"
#include "image/codecs/mjpeg.h"
#include "image/codecs/mpeg.h"
#include "image/codecs/msvideo1.h"
@ -209,6 +210,9 @@ Codec *createBitmapCodec(uint32 tag, int width, int height, int bitsPerPixel) {
return new CinepakDecoder(bitsPerPixel);
case MKTAG('I','V','3','2'):
return new Indeo3Decoder(width, height);
case MKTAG('I', 'V', '4', '1'):
case MKTAG('I', 'V', '4', '2'):
return new Indeo4Decoder(width, height);
#ifdef IMAGE_CODECS_TRUEMOTION1_H
case MKTAG('D','U','C','K'):
case MKTAG('d','u','c','k'):

View File

@ -0,0 +1,462 @@
/* 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.
*
*/
#include "image/codecs/indeo/get_bits.h"
#include "common/endian.h"
#include "common/textconsole.h"
/* Intel Indeo 4 bitstream reader
*
* Original copyright note:
* Copyright (c) 2004 Michael Niedermayer
*/
namespace Image {
namespace Indeo {
/* Macro documentation
* name
* arbitrary name which is used as prefix for local variables
*
* OPEN_READER(name)
* load index into local variable
*
* CLOSE_READER(name)
* store local index back into class state
*
* UPDATE_CACHE(name)
* Refill the internal cache from the bitstream.
* After this call at least MIN_CACHE_BITS will be available.
*
* GET_CACHE(name)
* Will output the contents of the internal cache,
* next bit is MSB of 32 or 64 bits (FIXME 64 bits).
*
* SHOW_UBITS(name, num)
* Will return the next num bits.
*
* SHOW_SBITS(name, num)
* Will return the next num bits and do sign extension.
*
* SKIP_BITS(name, num)
* Will skip over the next num bits.
* Note, this is equivalent to SKIP_CACHE; SKIP_COUNTER.
*
* SKIP_CACHE(name, num)
* Will remove the next num bits from the cache (note SKIP_COUNTER
* MUST be called before UPDATE_CACHE / CLOSE_READER).
*
* SKIP_COUNTER(name, num)
* Will increment the internal bit counter (see SKIP_CACHE & SKIP_BITS).
*
* LAST_SKIP_BITS(name, num)
* Like SKIP_BITS, to be used if next call is UPDATE_CACHE or CLOSE_READER.
*
* BITS_LEFT(name)
* Return the number of bits left
*
* For examples see getBits, show_bits, skip_bits, get_vlc.
*/
#define BITSTREAM_READER_LE
#ifdef LONG_BITSTREAM_READER
# define MIN_CACHE_BITS 32
#else
# define MIN_CACHE_BITS 25
#endif
#define NEG_USR32(a,s) (((uint32)(a)) >> (32 -(s)))
#define OPEN_READER_NOSIZE(name) \
unsigned int name ## _index = _index; \
unsigned int name ## _cache
#define OPEN_READER(name) OPEN_READER_NOSIZE(name)
#define BITS_AVAILABLE(name) 1
#define CLOSE_READER(name) _index = name ## _index
# ifdef LONG_BITSTREAM_READER
# define UPDATE_CACHE_LE(name) name ## _cache = \
AV_RL64(_buffer + (name ## _index >> 3)) >> (name ## _index & 7)
# define UPDATE_CACHE_BE(name) name ## _cache = \
AV_RB64(_buffer + (name ## _index >> 3)) >> (32 - (name ## _index & 7))
#else
# define UPDATE_CACHE_LE(name) name ## _cache = \
READ_LE_UINT32(_buffer + (name ## _index >> 3)) >> (name ## _index & 7)
# define UPDATE_CACHE_BE(name) name ## _cache = \
AV_RB32(_buffer + (name ## _index >> 3)) << (name ## _index & 7)
#endif
#ifdef BITSTREAM_READER_LE
# define UPDATE_CACHE(name) UPDATE_CACHE_LE(name)
# define SKIP_CACHE(name, num) name ## _cache >>= (num)
#else
# define UPDATE_CACHE(name) UPDATE_CACHE_BE(name)
# define SKIP_CACHE(name, num) name ## _cache <<= (num)
#endif
#define SKIP_COUNTER(name, num) name ## _index += (num)
#define BITS_LEFT(name) ((int)(_size_in_bits - name ## _index))
#define SKIP_BITS(name, num) \
do { \
SKIP_CACHE(name, num); \
SKIP_COUNTER(name, num); \
} while (0)
#define LAST_SKIP_BITS(name, num) SKIP_COUNTER(name, num)
#define SHOW_UBITS_LE(name, num) zeroExtend(name ## _cache, num)
#define SHOW_SBITS_LE(name, num) signExtend(name ## _cache, num)
#define SHOW_UBITS_BE(name, num) NEG_USR32(name ## _cache, num)
#define SHOW_SBITS_BE(name, num) NEG_SSR32(name ## _cache, num)
#ifdef BITSTREAM_READER_LE
# define SHOW_UBITS(name, num) SHOW_UBITS_LE(name, num)
# define SHOW_SBITS(name, num) SHOW_SBITS_LE(name, num)
#else
# define SHOW_UBITS(name, num) SHOW_UBITS_BE(name, num)
# define SHOW_SBITS(name, num) SHOW_SBITS_BE(name, num)
#endif
#define GET_CACHE(name) ((uint32) name ## _cache)
static int signExtend(int val, uint bits) {
uint shift = 8 * sizeof(int) - bits;
union { uint u; int s; } v = { (unsigned)val << shift };
return v.s >> shift;
}
static uint zeroExtend(uint val, uint bits) {
return (val << ((8 * sizeof(int)) - bits)) >> ((8 * sizeof(int)) - bits);
}
GetBits::GetBits(const byte *buffer, size_t totalBits) {
assert(buffer && totalBits < (INT_MAX - 7));
_buffer = buffer;
_sizeInBits = totalBits;
_sizeInBitsPlus8 = totalBits + 8;
_index = 0;
}
GetBits::GetBits(const GetBits &src) : _index(src._index), _buffer(src._buffer),
_sizeInBits(src._sizeInBits), _sizeInBitsPlus8(src._sizeInBitsPlus8) {
}
int GetBits::getXbits(int n) {
int sign;
int cache;
OPEN_READER(re);
assert(n > 0 && n <= 25);
UPDATE_CACHE(re);
cache = GET_CACHE(re);
sign = ~cache >> 31;
LAST_SKIP_BITS(re, n);
CLOSE_READER(re);
return (NEG_USR32(sign ^ cache, n) ^ sign) - sign;
}
int GetBits::getSbits(int n) {
int tmp;
OPEN_READER(re);
assert(n > 0 && n <= 25);
UPDATE_CACHE(re);
tmp = SHOW_SBITS(re, n);
LAST_SKIP_BITS(re, n);
CLOSE_READER(re);
return tmp;
}
/**
* Read 1-25 bits.
*/
uint GetBits::getBits(int n) {
int tmp;
OPEN_READER(re);
assert(n > 0 && n <= 25);
UPDATE_CACHE(re);
tmp = SHOW_UBITS(re, n);
LAST_SKIP_BITS(re, n);
CLOSE_READER(re);
return tmp;
}
int GetBits::getBitsZ(int n) {
return n ? getBits(n) : 0;
}
uint GetBits::getBitsLE(int n) {
int tmp;
OPEN_READER(re);
assert(n > 0 && n <= 25);
UPDATE_CACHE_LE(re);
tmp = SHOW_UBITS_LE(re, n);
LAST_SKIP_BITS(re, n);
CLOSE_READER(re);
return tmp;
}
uint GetBits::showBits(int n) {
int tmp;
OPEN_READER_NOSIZE(re);
assert(n > 0 && n <= 25);
UPDATE_CACHE(re);
tmp = SHOW_UBITS(re, n);
return tmp;
}
void GetBits::skipBits(int n) {
OPEN_READER(re);
LAST_SKIP_BITS(re, n);
CLOSE_READER(re);
}
uint GetBits::getBits1() {
uint index = _index;
uint8 result = _buffer[index >> 3];
#ifdef BITSTREAM_READER_LE
result >>= index & 7;
result &= 1;
#else
result <<= index & 7;
result >>= 8 - 1;
#endif
#if !UNCHECKED_BITSTREAM_READER
if (_index < _sizeInBitsPlus8)
#endif
index++;
_index = index;
return result;
}
uint GetBits::showBits1() {
return showBits(1);
}
void GetBits::skipBits1() {
skipBits(1);
}
/**
* Read 0-32 bits.
*/
uint GetBits::getBitsLong(int n) {
if (!n) {
return 0;
} else if (n <= MIN_CACHE_BITS) {
return getBits(n);
} else {
#ifdef BITSTREAM_READER_LE
unsigned ret = getBits(16);
return ret | (getBits(n - 16) << 16);
#else
unsigned ret = getBits(16) << (n - 16);
return ret | getBits(n - 16);
#endif
}
}
/**
* Read 0-64 bits.
*/
uint64 GetBits::getBits64(int n) {
if (n <= 32) {
return getBitsLong(n);
} else {
#ifdef BITSTREAM_READER_LE
uint64 ret = getBitsLong(32);
return ret | (uint64)getBitsLong(n - 32) << 32;
#else
uint64 ret = (uint64)getBitsLong(n - 32) << 32;
return ret | getBitsLong(32);
#endif
}
}
int GetBits::getSbitsLong(int n) {
return signExtend(getBitsLong(n), n);
}
/**
* Show 0-32 bits.
*/
uint GetBits::showBitsLong(int n) {
if (n <= MIN_CACHE_BITS) {
return showBits(n);
} else {
GetBits gb(*this);
return gb.getBitsLong(n);
}
}
int GetBits::checkMarker(void *logctx, const char *msg) {
int bit = getBits1();
if (!bit)
warning("Marker bit missing at %d of %d %s\n",
getBitsCount() - 1, _sizeInBits, msg);
return bit;
}
const byte *GetBits::alignGetBits() {
int n = -(int)getBitsCount() & 7;
if (n)
skipBits(n);
return _buffer + (_index >> 3);
}
/**
* If the vlc code is invalid and max_depth=1, then no bits will be removed.
* If the vlc code is invalid and max_depth>1, then the number of bits removed
* is undefined.
*/
#define GET_VLC(code, name, table, bits, max_depth) \
do { \
int n, nb_bits; \
unsigned int index; \
\
index = SHOW_UBITS(name, bits); \
code = table[index][0]; \
n = table[index][1]; \
\
if (max_depth > 1 && n < 0) { \
LAST_SKIP_BITS(name, bits); \
UPDATE_CACHE(name); \
\
nb_bits = -n; \
\
index = SHOW_UBITS(name, nb_bits) + code; \
code = table[index][0]; \
n = table[index][1]; \
if (max_depth > 2 && n < 0) { \
LAST_SKIP_BITS(name, nb_bits); \
UPDATE_CACHE(name); \
\
nb_bits = -n; \
\
index = SHOW_UBITS(name, nb_bits) + code; \
code = table[index][0]; \
n = table[index][1]; \
} \
} \
SKIP_BITS(name, n); \
} while (0)
#define GET_RL_VLC(level, run, name, table, bits, \
max_depth, need_update) \
do { \
int n, nb_bits; \
unsigned int index; \
\
index = SHOW_UBITS(name, bits); \
level = table[index].level; \
n = table[index].len; \
\
if (max_depth > 1 && n < 0) { \
SKIP_BITS(name, bits); \
if (need_update) { \
UPDATE_CACHE(name); \
} \
\
nb_bits = -n; \
\
index = SHOW_UBITS(name, nb_bits) + level; \
level = table[index].level; \
n = table[index].len; \
if (max_depth > 2 && n < 0) { \
LAST_SKIP_BITS(name, nb_bits); \
if (need_update) { \
UPDATE_CACHE(name); \
} \
nb_bits = -n; \
\
index = SHOW_UBITS(name, nb_bits) + level; \
level = table[index].level; \
n = table[index].len; \
} \
} \
run = table[index].run; \
SKIP_BITS(name, n); \
} while (0)
/**
* Parse a vlc code.
* @param bits is the number of bits which will be read at once, must be
* identical to nb_bits in init_vlc()
* @param max_depth is the number of times bits bits must be read to completely
* read the longest vlc code
* = (max_vlc_length + bits - 1) / bits
*/
int GetBits::getVLC2(int (*table)[2], int bits, int maxDepth) {
int code;
OPEN_READER(re);
UPDATE_CACHE(re);
GET_VLC(code, re, table, bits, maxDepth);
CLOSE_READER(re);
return code;
}
int GetBits::decode012() {
int n;
n = getBits1();
if (n == 0)
return 0;
else
return getBits1() + 1;
}
int GetBits::decode210() {
if (getBits1())
return 0;
else
return 2 - getBits1();
}
int GetBits::skip1stop8dataBits() {
if (getBitsLeft() <= 0)
return -1;
while (getBits1()) {
skipBits(8);
if (getBitsLeft() <= 0)
return -1;
}
return 0;
}
} // End of namespace Indeo
} // End of namespace Image

View File

@ -0,0 +1,169 @@
/* 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.
*
*/
#include "common/scummsys.h"
/* Intel Indeo 4 bitstream reader
*
* Original copyright note:
* Copyright (c) 2004 Michael Niedermayer
*/
#ifndef IMAGE_CODECS_INDEO_GET_BITS_H
#define IMAGE_CODECS_INDEO_GET_BITS_H
#include "common/scummsys.h"
namespace Image {
namespace Indeo {
#define AV_INPUT_BUFFER_PADDING_SIZE 32
/**
* Intel Indeo Bitstream reader
*/
class GetBits {
private:
const byte *_buffer;
uint _index;
uint _sizeInBits;
uint _sizeInBitsPlus8;
public:
/**
* Constructor
* @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes
* larger than the actual read bits because some optimized bitstream
* readers read 32 or 64 bit at once and could read over the end
* @param bit_size the size of the buffer in bits
* @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow.
*/
GetBits(const byte *buffer, size_t totalBits);
GetBits(const GetBits &src);
/**
* Returns the number of bits read
*/
uint getBitsCount() const { return _index; }
/**
* The number of bits left
*/
int getBitsLeft() const { return _sizeInBits - _index; }
void skipBitsLong(uint n) { _index += n; }
/**
* Read MPEG-1 dc-style VLC (sign bit + mantissa with no MSB).
* if MSB not set it is negative
* @param n length in bits
*/
int getXbits(int n);
/**
* Returns the next n bits, and does sign extension
*/
int getSbits(int n);
/**
* Read 1-25 bits.
*/
uint getBits(int n);
/**
* Read 0-25 bits.
*/
int getBitsZ(int n);
uint getBitsLE(int n);
/**
* Show 1-25 bits.
* Returns the data without updating the index
*/
uint showBits(int n);
/**
* Skips a specified number of bits
*/
void skipBits(int n);
/**
* Returns the next bit
*/
uint getBits1();
/**
* Shows the next following bit
*/
uint showBits1();
/**
* Skips the next bit
*/
void skipBits1();
/**
* Read 0-32 bits.
*/
uint getBitsLong(int n);
/**
* Read 0-64 bits.
*/
uint64 getBits64(int n);
/**
* Read 0-32 bits as a signed integer.
*/
int getSbitsLong(int n);
/**
* Show 0-32 bits.
*/
uint showBitsLong(int n);
int checkMarker(void *logctx, const char *msg);
/**
* Parse a VLC code.
* @param bits is the number of bits which will be read at once, must be
* identical to nb_bits in init_vlc()
* @param max_depth is the number of times bits bits must be read to completely
* read the longest vlc code
* = (max_vlc_length + bits - 1) / bits
*/
int getVLC2(int(*table)[2], int bits, int maxDepth);
int decode012();
int decode210();
int skip1stop8dataBits();
const byte *alignGetBits();
};
} // End of namespace Indeo
} // End of namespace Image
#endif

81
image/codecs/indeo4.cpp Normal file
View File

@ -0,0 +1,81 @@
/* 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.
*
*/
#include "common/scummsys.h"
/* Intel Indeo 4 decompressor, derived from ffmpeg.
*
* Original copyright note: * Intel Indeo 3 (IV31, IV32, etc.) video decoder for ffmpeg
* written, produced, and directed by Alan Smithee
*/
#include "common/system.h"
#include "common/endian.h"
#include "common/stream.h"
#include "common/textconsole.h"
#include "common/util.h"
#include "graphics/yuv_to_rgb.h"
#include "image/codecs/indeo4.h"
#include "image/codecs/indeo/get_bits.h"
namespace Image {
Indeo4Decoder::Indeo4Decoder(uint16 width, uint16 height) {
_pixelFormat = g_system->getScreenFormat();
_surface = new Graphics::ManagedSurface();
_surface->create(width, height, _pixelFormat);
}
Indeo4Decoder::~Indeo4Decoder() {
delete _surface;
}
bool Indeo4Decoder::isIndeo4(Common::SeekableReadStream &stream) {
// Less than 16 bytes? This can't be right
if (stream.size() < 16)
return false;
// Read in the start of the data
byte buffer[16];
stream.read(buffer, 16);
stream.seek(-16, SEEK_CUR);
// Validate the first 18-bit word has the correct identifier
Indeo::GetBits gb(buffer, 16 * 8);
bool isIndeo4 = gb.getBits(18) == 0x3FFF8;
return isIndeo4;
}
const Graphics::Surface *Indeo4Decoder::decodeFrame(Common::SeekableReadStream &stream) {
// Not Indeo 4? Fail
if (!isIndeo4(stream))
return 0;
// TODO
return nullptr;
}
} // End of namespace Image

64
image/codecs/indeo4.h Normal file
View File

@ -0,0 +1,64 @@
/* 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.
*
*/
#include "common/scummsys.h"
/* Intel Indeo 4 decompressor, derived from ffmpeg.
*
* Original copyright note:
* Intel Indeo 4 (IV31, IV32, etc.) video decoder for ffmpeg
* written, produced, and directed by Alan Smithee
*/
#ifndef IMAGE_CODECS_INDEO4_H
#define IMAGE_CODECS_INDEO4_H
#include "image/codecs/codec.h"
#include "graphics/managed_surface.h"
namespace Image {
/**
* Intel Indeo 4 decoder.
*
* Used by AVI.
*
* Used in video:
* - AVIDecoder
*/
class Indeo4Decoder : public Codec {
public:
Indeo4Decoder(uint16 width, uint16 height);
~Indeo4Decoder();
const Graphics::Surface *decodeFrame(Common::SeekableReadStream &stream);
Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; }
static bool isIndeo4(Common::SeekableReadStream &stream);
private:
Graphics::PixelFormat _pixelFormat;
Graphics::ManagedSurface *_surface;
};
} // End of namespace Image
#endif

View File

@ -13,6 +13,7 @@ MODULE_OBJS := \
codecs/cinepak.o \
codecs/codec.o \
codecs/indeo3.o \
codecs/indeo4.o \
codecs/mjpeg.o \
codecs/msrle.o \
codecs/msrle4.o \
@ -21,7 +22,8 @@ MODULE_OBJS := \
codecs/rpza.o \
codecs/smc.o \
codecs/svq1.o \
codecs/truemotion1.o
codecs/truemotion1.o \
codecs/indeo/get_bits.o
ifdef USE_MPEG2
MODULE_OBJS += \