Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,89 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef IMAGE_CODECS_INDEO_GET_BITS_H
#define IMAGE_CODECS_INDEO_GET_BITS_H
#include "common/bitstream.h"
namespace Image {
namespace Indeo {
/**
* Intel Indeo Bitstream reader
*/
class GetBits : public Common::BitStreamMemory8LSB {
public:
/**
* Constructor
*/
GetBits(const byte *dataPtr, uint32 dataSize) : Common::BitStreamMemory8LSB(new Common::BitStreamMemoryStream(dataPtr, dataSize), DisposeAfterUse::YES) {}
/**
* The number of bits left
*/
int getBitsLeft() const { return size() - pos(); }
/**
* Parse a VLC code.
* @param bits is the number of bits which will be read at once, must be
* identical to nbBits in init_vlc()
* @param maxDepth is the number of times bits bits must be read to completely
* read the longest vlc code
* = (max_vlc_length + bits - 1) / bits
*/
template <int maxDepth, int bits>
int getVLC2(int16 (*table)[2]) {
int code;
int n, nbBits;
unsigned int index;
index = peekBits<bits>();
code = table[index][0];
n = table[index][1];
if (maxDepth > 1 && n < 0) {
skip(bits);
nbBits = -n;
index = peekBits(nbBits) + code;
code = table[index][0];
n = table[index][1];
if (maxDepth > 2 && n < 0) {
skip(nbBits);
nbBits = -n;
index = peekBits(nbBits) + code;
code = table[index][0];
n = table[index][1];
}
}
skip(n);
return code;
}
};
} // End of namespace Indeo
} // End of namespace Image
#endif

1719
image/codecs/indeo/indeo.cpp Normal file

File diff suppressed because it is too large Load Diff

604
image/codecs/indeo/indeo.h Normal file
View File

@@ -0,0 +1,604 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/scummsys.h"
#include "graphics/surface.h"
#include "image/codecs/codec.h"
/* Common structures, macros, and base class shared by both Indeo4 and
* Indeo5 decoders, derived from ffmpeg. We don't currently support Indeo5
* decoding, but just in case we eventually need it, this is kept as a separate
* file like it is in ffmpeg.
*
* Original copyright note: * Intel Indeo 4 (IV41, IV42, etc.) video decoder for ffmpeg
* written, produced, and directed by Alan Smithee
*/
#ifndef IMAGE_CODECS_INDEO_INDEO_H
#define IMAGE_CODECS_INDEO_INDEO_H
#include "image/codecs/indeo/get_bits.h"
#include "image/codecs/indeo/vlc.h"
namespace Image {
namespace Indeo {
/**
* Indeo 4 frame types.
*/
enum {
IVI4_FRAMETYPE_INTRA = 0,
IVI4_FRAMETYPE_INTRA1 = 1, ///< intra frame with slightly different bitstream coding
IVI4_FRAMETYPE_INTER = 2, ///< non-droppable P-frame
IVI4_FRAMETYPE_BIDIR = 3, ///< bidirectional frame
IVI4_FRAMETYPE_INTER_NOREF = 4, ///< droppable P-frame
IVI4_FRAMETYPE_NULL_FIRST = 5, ///< empty frame with no data
IVI4_FRAMETYPE_NULL_LAST = 6 ///< empty frame with no data
};
enum {
IVI_MB_HUFF = 0, /// Huffman table is used for coding macroblocks
IVI_BLK_HUFF = 1 /// Huffman table is used for coding blocks
};
/**
* Declare inverse transform function types
*/
typedef void (InvTransformPtr)(const int32 *in, int16 *out, uint32 pitch, const uint8 *flags);
typedef void (DCTransformPtr)(const int32 *in, int16 *out, uint32 pitch, int blkSize);
typedef void (*IviMCFunc)(int16 *buf, const int16 *refBuf, uint32 pitch, int mcType);
typedef void (*IviMCAvgFunc)(int16 *buf, const int16 *refBuf1, const int16 *refBuf2,
uint32 pitch, int mcType, int mcType2);
///< max number of bits of the ivi's huffman codes
#define IVI_VLC_BITS 13
#define IVI5_IS_PROTECTED 0x20
/**
* convert unsigned values into signed ones (the sign is in the LSB)
*/
#define IVI_TOSIGNED(val) (-(((val) >> 1) ^ -((val) & 1)))
/**
* calculate number of macroblocks in a tile
*/
#define IVI_MBs_PER_TILE(tileWidth, tileHeight, mbSize) \
((((tileWidth) + (mbSize) - 1) / (mbSize)) * (((tileHeight) + (mbSize) - 1) / (mbSize)))
/**
* huffman codebook descriptor
*/
struct IVIHuffDesc {
int32 _numRows;
uint8 _xBits[16];
/**
* Generate a huffman codebook from the given descriptor
* and convert it into the FFmpeg VLC table.
*
* @param[out] vlc Where to place the generated VLC table
* @param[in] flag Flag: true - for static or false for dynamic tables
* @returns result code: 0 - OK, -1 = error (invalid codebook descriptor)
*/
int createHuffFromDesc(VLC *vlc, bool flag) const;
/**
* Compare two huffman codebook descriptors.
*
* @param[in] desc2 Ptr to the 2nd descriptor to compare
* @returns comparison result: 0 - equal, 1 - not equal
*/
bool huffDescCompare(const IVIHuffDesc *desc2) const;
/**
* Copy huffman codebook descriptors.
*
* @param[in] src ptr to the source descriptor
*/
void huffDescCopy(const IVIHuffDesc *src);
};
struct IVI45DecContext;
/**
* Macroblock/block huffman table descriptor
*/
struct IVIHuffTab {
public:
int32 _tabSel; /// index of one of the predefined tables
/// or "7" for custom one
VLC * _tab; /// pointer to the table associated with tab_sel
/// the following are used only when tab_sel == 7
IVIHuffDesc _custDesc; /// custom Huffman codebook descriptor
VLC _custTab; /// vlc table for custom codebook
/**
* Constructor
*/
IVIHuffTab();
/**
* Decode a huffman codebook descriptor from the bitstream
* and select specified huffman table.
*
* @param[in] ctx Decoder context
* @param[in] descCoded Flag signalling if table descriptor was coded
* @param[in] whichTab Codebook purpose (IVI_MB_HUFF or IVI_BLK_HUFF)
* @returns Zero on success, negative value otherwise
*/
int decodeHuffDesc(IVI45DecContext *ctx, int descCoded, int whichTab);
};
/**
* run-value (RLE) table descriptor
*/
struct RVMapDesc {
uint8 _eobSym; ///< end of block symbol
uint8 _escSym; ///< escape symbol
uint8 _runtab[256];
int8 _valtab[256];
};
/**
* information for Indeo macroblock (16x16, 8x8 or 4x4)
*/
struct IVIMbInfo {
int16 _xPos;
int16 _yPos;
uint32 _bufOffs; ///< address in the output buffer for this mb
uint8 _type; ///< macroblock type: 0 - INTRA, 1 - INTER
uint8 _cbp; ///< coded block pattern
int8 _qDelta; ///< quant delta
int8 _mvX; ///< motion vector (x component)
int8 _mvY; ///< motion vector (y component)
int8 _bMvX; ///< second motion vector (x component)
int8 _bMvY; ///< second motion vector (y component)
IVIMbInfo();
};
/**
* information for Indeo tile
*/
struct IVITile {
int _xPos;
int _yPos;
int _width;
int _height;
int _mbSize;
bool _isEmpty;
int _dataSize; ///< size of the data in bytes
int _numMBs; ///< number of macroblocks in this tile
IVIMbInfo * _mbs; ///< array of macroblock descriptors
IVIMbInfo * _refMbs; ///< ptr to the macroblock descriptors of the reference tile
IVITile();
};
/**
* information for Indeo wavelet band
*/
struct IVIBandDesc {
int _plane; ///< plane number this band belongs to
int _bandNum; ///< band number
int _width;
int _height;
int _aHeight; ///< aligned band height
const uint8 * _dataPtr; ///< ptr to the first byte of the band data
int _dataSize; ///< size of the band data
int16 * _buf; ///< pointer to the output buffer for this band
int16 * _refBuf; ///< pointer to the reference frame buffer (for motion compensation)
int16 * _bRefBuf; ///< pointer to the second reference frame buffer (for motion compensation)
int16 * _bufs[4]; ///< array of pointers to the band buffers
int _pitch; ///< _pitch associated with the buffers above
bool _isEmpty;
int _mbSize; ///< macroblock size
int _blkSize; ///< block size
uint8 _isHalfpel; ///< precision of the motion compensation: 0 - fullpel, 1 - halfpel
bool _inheritMv; ///< tells if motion vector is inherited from reference macroblock
bool _inheritQDelta; ///< tells if quantiser delta is inherited from reference macroblock
bool _qdeltaPresent; ///< tells if Qdelta signal is present in the bitstream (Indeo5 only)
int _quantMat; ///< dequant matrix index
int _globQuant; ///< quant base for this band
const uint8 * _scan; ///< ptr to the scan pattern
int _scanSize; ///< size of the scantable
IVIHuffTab _blkVlc; ///< vlc table for decoding block data
int _numCorr; ///< number of correction entries
uint8 _corr[61 * 2]; ///< rvmap correction pairs
int _rvmapSel; ///< rvmap table selector
RVMapDesc * _rvMap; ///< ptr to the RLE table for this band
int _numTiles; ///< number of tiles in this band
IVITile * _tiles; ///< array of tile descriptors
InvTransformPtr *_invTransform;
int _transformSize;
DCTransformPtr *_dcTransform;
bool _is2dTrans;
int32 _checksum; ///< for debug purposes
int _checksumPresent;
int _bufSize; ///< band buffer size in bytes
const uint16 * _intraBase; ///< quantization matrix for intra blocks
const uint16 * _interBase; ///< quantization matrix for inter blocks
const uint8 * _intraScale; ///< quantization coefficient for intra blocks
const uint8 * _interScale; ///< quantization coefficient for inter blocks
IVIBandDesc();
int initTiles(IVITile *refTile, int p, int b, int tHeight, int tWidth);
};
struct IVIPicConfig {
uint16 _picWidth;
uint16 _picHeight;
uint16 _chromaWidth;
uint16 _chromaHeight;
uint16 _tileWidth;
uint16 _tileHeight;
uint8 _lumaBands;
uint8 _chromaBands;
IVIPicConfig();
/**
* Compare some properties of two pictures
*/
bool ivi_pic_config_cmp(const IVIPicConfig &cfg2);
};
/**
* color plane (luma or chroma) information
*/
struct IVIPlaneDesc {
uint16 _width;
uint16 _height;
uint8 _numBands; ///< number of bands this plane subdivided into
IVIBandDesc * _bands; ///< array of band descriptors
IVIPlaneDesc();
static int initPlanes(IVIPlaneDesc *planes, const IVIPicConfig *cfg, bool isIndeo4);
static int initTiles(IVIPlaneDesc *planes, int tileWidth, int tileHeight);
/**
* Free planes, bands and macroblocks buffers.
*
* @param[in] planes pointer to the array of the plane descriptors
*/
static void freeBuffers(IVIPlaneDesc *planes);
/**
* Check if the given dimension of an image is valid, meaning that all
* bytes of the image can be addressed with a signed int.
*
* @param w the width of the picture
* @param h the height of the picture
* @param log_offset the offset to sum to the log level for logging with log_ctx
* @returns >= 0 if valid, a negative error code otherwise
*/
static int checkImageSize(unsigned int w, unsigned int h, int logOffset);
};
struct AVFrame {
/**
* Dimensions
*/
int _width, _height;
#define AV_NUM_DATA_POINTERS 3
/**
* pointer to the picture/channel planes.
* This might be different from the first allocated byte
*
* Some decoders access areas outside 0,0 - width,height, please
* see avcodec_align_dimensions2(). Some filters and swscale can read
* up to 16 bytes beyond the planes, if these filters are to be used,
* then 16 extra bytes must be allocated.
*
* NOTE: Except for hwaccel formats, pointers not needed by the format
* MUST be set to NULL.
*/
uint8 *_data[AV_NUM_DATA_POINTERS];
/**
* For video, size in bytes of each picture line.
* For audio, size in bytes of each plane.
*
* For audio, only linesize[0] may be set. For planar audio, each channel
* plane must be the same size.
*
* For video the linesizes should be multiples of the CPUs alignment
* preference, this is 16 or 32 for modern desktop CPUs.
* Some code requires such alignment other code can be slower without
* correct alignment, for yet other it makes no difference.
*
* @note The linesize may be larger than the size of usable data -- there
* may be extra padding present for performance reasons.
*/
int _linesize[AV_NUM_DATA_POINTERS];
/**
* Constructor
*/
AVFrame();
/**
* Destructor
*/
~AVFrame() { freeFrame(); }
/**
* Sets the frame dimensions
*/
int setDimensions(uint16 width, uint16 height);
/**
* Get a buffer for a frame
*/
int getBuffer(int flags);
/**
* Frees any data loaded for the frame
*/
void freeFrame();
};
struct IVI45DecContext {
friend struct IVIHuffTab;
private:
VLC_TYPE _tableData[8192 * 16][2];
VLC _iviMbVlcTabs[8]; ///< static macroblock Huffman tables
VLC _iviBlkVlcTabs[8]; ///< static block Huffman tables
public:
GetBits * _gb;
RVMapDesc _rvmapTabs[9]; ///< local corrected copy of the static rvmap tables
uint32 _frameNum;
int _frameType;
int _prevFrameType; ///< frame type of the previous frame
uint32 _dataSize; ///< size of the frame data in bytes from picture header
int _isScalable;
const uint8 * _frameData; ///< input frame data pointer
int _interScal; ///< signals a sequence of scalable inter frames
uint32 _frameSize; ///< frame size in bytes
uint32 _picHdrSize; ///< picture header size in bytes
uint8 _frameFlags;
uint16 _checksum; ///< frame _checksum
IVIPicConfig _picConf;
IVIPlaneDesc _planes[3]; ///< color planes
int _bufSwitch; ///< used to switch between three buffers
int _dstBuf; ///< buffer index for the currently decoded frame
int _refBuf; ///< inter frame reference buffer index
int _ref2Buf; ///< temporal storage for switching buffers
int _bRefBuf; ///< second reference frame buffer index
IVIHuffTab _mbVlc; ///< current macroblock table descriptor
IVIHuffTab _blkVlc; ///< current block table descriptor
IVIHuffTab _transVlc; ///< current transparency table descriptor
uint8 _rvmapSel;
bool _inImf;
bool _inQ; ///< flag for explicitly stored quantiser delta
uint8 _picGlobQuant;
uint8 _unknown1;
uint16 _gopHdrSize;
uint8 _gopFlags;
uint32 _lockWord;
bool _hasBFrames;
bool _hasTransp; ///< transparency mode enabled
bool _usesTiling;
bool _usesHaar;
bool _usesFullpel;
bool _gopInvalid;
int _bufInvalid[4];
bool _isIndeo4;
uint32 _transKeyColor;
AVFrame * _pFrame;
bool _gotPFrame;
IVI45DecContext();
private:
/**
* Initial Run-value (RLE) tables.
*/
static const RVMapDesc _ff_ivi_rvmap_tabs[9];
};
class IndeoDecoderBase : public Codec {
private:
/**
* Decode an Indeo 4 or 5 band.
*
* @param[in,out] band ptr to the band descriptor
* @returns result code: 0 = OK, -1 = error
*/
int decode_band(IVIBandDesc *band);
/**
* Haar wavelet recomposition filter for Indeo 4
*
* @param[in] plane Pointer to the descriptor of the plane being processed
* @param[out] dst pointer to the destination buffer
* @param[in] dstPitch Pitch of the destination buffer
*/
void recomposeHaar(const IVIPlaneDesc *plane, uint8 *dst, const int dstPitch);
/**
* 5/3 wavelet recomposition filter for Indeo5
*
* @param[in] plane Pointer to the descriptor of the plane being processed
* @param[out] dst Pointer to the destination buffer
* @param[in] dstPitch Pitch of the destination buffer
*/
void recompose53(const IVIPlaneDesc *plane, uint8 *dst, const int dstPitch);
/*
* Convert and output the current plane.
* This conversion is done by adding back the bias value of 128
* (subtracted in the encoder) and clipping the result.
*
* @param[in] plane Pointer to the descriptor of the plane being processed
* @param[out] dst Pointer to the buffer receiving converted pixels
* @param[in] dstPitch Pitch for moving to the next y line
*/
void outputPlane(IVIPlaneDesc *plane, uint8 *dst, int dstPitch);
/**
* Handle empty tiles by performing data copying and motion
* compensation respectively.
*
* @param[in] band Pointer to the band descriptor
* @param[in] tile Pointer to the tile descriptor
* @param[in] mvScale Scaling factor for motion vectors
*/
int processEmptyTile(IVIBandDesc *band, IVITile *tile, int32 mvScale);
/*
* Decode size of the tile data.
* The size is stored as a variable-length field having the following format:
* if (tile_data_size < 255) than this field is only one byte long
* if (tile_data_size >= 255) than this field four is byte long: 0xFF X1 X2 X3
* where X1-X3 is size of the tile data
*
* @param[in,out] gb the GetBit context
* @returns Size of the tile data in bytes
*/
int decodeTileDataSize(GetBits *gb);
/*
* Decode block data:
* extract huffman-coded transform coefficients from the bitstream,
* dequantize them, apply inverse transform and motion compensation
* in order to reconstruct the picture.
*
* @param[in,out] gb The GetBit context
* @param[in] band Pointer to the band descriptor
* @param[in] tile Pointer to the tile descriptor
* @returns Result code: 0 - OK, -1 = error (corrupted blocks data)
*/
int decodeBlocks(GetBits *gb, IVIBandDesc *band, IVITile *tile);
int iviMc(IVIBandDesc *band, IviMCFunc mc, IviMCAvgFunc mcAvg,
int offs, int mvX, int mvY, int mvX2, int mvY2, int mcType, int mcType2);
int decodeCodedBlocks(GetBits *gb, IVIBandDesc *band,
IviMCFunc mc, IviMCAvgFunc mcAvg, int mvX, int mvY,
int mvX2, int mvY2, int32 *prevDc, int isIntra,
int mcType, int mcType2, uint32 quant, int offs);
int iviDcTransform(IVIBandDesc *band, int32 *prevDc, int bufOffs,
int blkSize);
protected:
IVI45DecContext _ctx;
uint16 _width;
uint16 _height;
uint _bitsPerPixel;
Graphics::PixelFormat _pixelFormat;
Graphics::Surface *_surface;
/**
* Scan patterns shared between indeo4 and indeo5
*/
static const uint8 _ffIviVerticalScan8x8[64];
static const uint8 _ffIviHorizontalScan8x8[64];
static const uint8 _ffIviDirectScan4x4[16];
protected:
/**
* Returns the pixel format for the decoder's surface
*/
Graphics::PixelFormat getPixelFormat() const override { return _pixelFormat; }
/**
* Select the preferred format to use, for codecs where this is faster than converting
* the image afterwards. Returns true if supported, and false otherwise.
*/
bool setOutputPixelFormat(const Graphics::PixelFormat &format) override {
if (format.bytesPerPixel != 2 && format.bytesPerPixel != 4)
return false;
_pixelFormat = format;
return true;
}
/**
* Decode the Indeo picture header.
* @returns 0 = Ok, negative number = error
*/
virtual int decodePictureHeader() = 0;
/**
* Rearrange decoding and reference buffers.
*/
virtual void switchBuffers() = 0;
virtual bool isNonNullFrame() const = 0;
/**
* Decode Indeo band header.
*
* @param[in,out] band Pointer to the band descriptor
* @returns Result code: 0 = OK, negative number = error
*/
virtual int decodeBandHeader(IVIBandDesc *band) = 0;
/**
* Decode information (block type, _cbp, quant delta, motion vector)
* for all macroblocks in the current tile.
*
* @param[in,out] band Pointer to the band descriptor
* @param[in,out] tile Pointer to the tile descriptor
* @returns Result code: 0 = OK, negative number = error
*/
virtual int decodeMbInfo(IVIBandDesc *band, IVITile *tile) = 0;
/**
* Decodes optional transparency data within Indeo frames
*/
virtual int decodeTransparency() { return -1; }
/**
* Decodes the Indeo frame from the bit reader already
* loaded into the context
*/
int decodeIndeoFrame();
/**
* scale motion vector
*/
int scaleMV(int mv, int mvScale);
public:
IndeoDecoderBase(uint16 width, uint16 height, uint bitsPerPixel);
~IndeoDecoderBase() override;
};
} // End of namespace Indeo
} // End of namespace Image
#endif

View File

@@ -0,0 +1,607 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/* VLC code
*
* Original copyright note: * Intel Indeo 4 (IV41, IV42, etc.) video decoder for ffmpeg
* written, produced, and directed by Alan Smithee
*/
#include "image/codecs/indeo/indeo_dsp.h"
namespace Image {
namespace Indeo {
/**
* butterfly operation for the inverse Haar transform
*/
#define IVI_HAAR_BFLY(s1, s2, o1, o2, t) \
t = ((s1) - (s2)) >> 1;\
o1 = ((s1) + (s2)) >> 1;\
o2 = (t);\
/**
* inverse 8-point Haar transform
*/
#define INV_HAAR8(s1, s5, s3, s7, s2, s4, s6, s8,\
d1, d2, d3, d4, d5, d6, d7, d8,\
t0, t1, t2, t3, t4, t5, t6, t7, t8) {\
t1 = (s1) << 1; t5 = (s5) << 1;\
IVI_HAAR_BFLY(t1, t5, t1, t5, t0); IVI_HAAR_BFLY(t1, s3, t1, t3, t0);\
IVI_HAAR_BFLY(t5, s7, t5, t7, t0); IVI_HAAR_BFLY(t1, s2, t1, t2, t0);\
IVI_HAAR_BFLY(t3, s4, t3, t4, t0); IVI_HAAR_BFLY(t5, s6, t5, t6, t0);\
IVI_HAAR_BFLY(t7, s8, t7, t8, t0);\
d1 = COMPENSATE(t1);\
d2 = COMPENSATE(t2);\
d3 = COMPENSATE(t3);\
d4 = COMPENSATE(t4);\
d5 = COMPENSATE(t5);\
d6 = COMPENSATE(t6);\
d7 = COMPENSATE(t7);\
d8 = COMPENSATE(t8); }
/**
* inverse 4-point Haar transform
*/
#define INV_HAAR4(s1, s3, s5, s7, d1, d2, d3, d4, t0, t1, t2, t3, t4) {\
IVI_HAAR_BFLY(s1, s3, t0, t1, t4);\
IVI_HAAR_BFLY(t0, s5, t2, t3, t4);\
d1 = COMPENSATE(t2);\
d2 = COMPENSATE(t3);\
IVI_HAAR_BFLY(t1, s7, t2, t3, t4);\
d3 = COMPENSATE(t2);\
d4 = COMPENSATE(t3); }
void IndeoDSP::ffIviInverseHaar8x8(const int32 *in, int16 *out, uint32 pitch,
const uint8 *flags) {
int32 tmp[64];
int t0, t1, t2, t3, t4, t5, t6, t7, t8;
// apply the InvHaar8 to all columns
#define COMPENSATE(x) (x)
const int32 *src = in;
int32 *dst = tmp;
for (int i = 0; i < 8; i++) {
if (flags[i]) {
// pre-scaling
int shift = !(i & 4);
int sp1 = src[ 0] << shift;
int sp2 = src[ 8] << shift;
int sp3 = src[16] << shift;
int sp4 = src[24] << shift;
INV_HAAR8( sp1, sp2, sp3, sp4,
src[32], src[40], src[48], src[56],
dst[ 0], dst[ 8], dst[16], dst[24],
dst[32], dst[40], dst[48], dst[56],
t0, t1, t2, t3, t4, t5, t6, t7, t8);
} else {
dst[ 0] = dst[ 8] = dst[16] = dst[24] =
dst[32] = dst[40] = dst[48] = dst[56] = 0;
}
src++;
dst++;
}
#undef COMPENSATE
// apply the InvHaar8 to all rows
#define COMPENSATE(x) (x)
src = tmp;
for (int i = 0; i < 8; i++) {
if (!src[0] && !src[1] && !src[2] && !src[3] &&
!src[4] && !src[5] && !src[6] && !src[7]) {
memset(out, 0, 8 * sizeof(out[0]));
} else {
INV_HAAR8(src[0], src[1], src[2], src[3],
src[4], src[5], src[6], src[7],
out[0], out[1], out[2], out[3],
out[4], out[5], out[6], out[7],
t0, t1, t2, t3, t4, t5, t6, t7, t8);
}
src += 8;
out += pitch;
}
#undef COMPENSATE
}
void IndeoDSP::ffIviRowHaar8(const int32 *in, int16 *out, uint32 pitch,
const uint8 *flags) {
int t0, t1, t2, t3, t4, t5, t6, t7, t8;
// apply the InvHaar8 to all rows
#define COMPENSATE(x) (x)
for (int i = 0; i < 8; i++) {
if ( !in[0] && !in[1] && !in[2] && !in[3]
&& !in[4] && !in[5] && !in[6] && !in[7]) {
memset(out, 0, 8 * sizeof(out[0]));
} else {
INV_HAAR8(in[0], in[1], in[2], in[3],
in[4], in[5], in[6], in[7],
out[0], out[1], out[2], out[3],
out[4], out[5], out[6], out[7],
t0, t1, t2, t3, t4, t5, t6, t7, t8);
}
in += 8;
out += pitch;
}
#undef COMPENSATE
}
void IndeoDSP::ffIviColHaar8(const int32 *in, int16 *out, uint32 pitch,
const uint8 *flags) {
int t0, t1, t2, t3, t4, t5, t6, t7, t8;
// apply the InvHaar8 to all columns
#define COMPENSATE(x) (x)
for (int i = 0; i < 8; i++) {
if (flags[i]) {
INV_HAAR8(in[ 0], in[ 8], in[16], in[24],
in[32], in[40], in[48], in[56],
out[0 * pitch], out[1 * pitch],
out[2 * pitch], out[3 * pitch],
out[4 * pitch], out[5 * pitch],
out[6 * pitch], out[7 * pitch],
t0, t1, t2, t3, t4, t5, t6, t7, t8);
} else {
out[0 * pitch] = out[1 * pitch] =
out[2 * pitch] = out[3 * pitch] =
out[4 * pitch] = out[5 * pitch] =
out[6 * pitch] = out[7 * pitch] = 0;
}
in++;
out++;
}
#undef COMPENSATE
}
void IndeoDSP::ffIviInverseHaar4x4(const int32 *in, int16 *out, uint32 pitch,
const uint8 *flags) {
int32 tmp[16];
int t0, t1, t2, t3, t4;
// apply the InvHaar4 to all columns
#define COMPENSATE(x) (x)
const int32 *src = in;
int32 *dst = tmp;
for (int i = 0; i < 4; i++) {
if (flags[i]) {
// pre-scaling
int shift = !(i & 2);
int sp1 = src[0] << shift;
int sp2 = src[4] << shift;
INV_HAAR4( sp1, sp2, src[8], src[12],
dst[0], dst[4], dst[8], dst[12],
t0, t1, t2, t3, t4);
} else {
dst[0] = dst[4] = dst[8] = dst[12] = 0;
}
src++;
dst++;
}
#undef COMPENSATE
// apply the InvHaar8 to all rows
#define COMPENSATE(x) (x)
src = tmp;
for (int i = 0; i < 4; i++) {
if (!src[0] && !src[1] && !src[2] && !src[3]) {
memset(out, 0, 4 * sizeof(out[0]));
} else {
INV_HAAR4(src[0], src[1], src[2], src[3],
out[0], out[1], out[2], out[3],
t0, t1, t2, t3, t4);
}
src += 4;
out += pitch;
}
#undef COMPENSATE
}
void IndeoDSP::ffIviRowHaar4(const int32 *in, int16 *out, uint32 pitch,
const uint8 *flags) {
int t0, t1, t2, t3, t4;
// apply the InvHaar4 to all rows
#define COMPENSATE(x) (x)
for (int i = 0; i < 4; i++) {
if (!in[0] && !in[1] && !in[2] && !in[3]) {
memset(out, 0, 4 * sizeof(out[0]));
} else {
INV_HAAR4(in[0], in[1], in[2], in[3],
out[0], out[1], out[2], out[3],
t0, t1, t2, t3, t4);
}
in += 4;
out += pitch;
}
#undef COMPENSATE
}
void IndeoDSP::ffIviColHaar4(const int32 *in, int16 *out, uint32 pitch,
const uint8 *flags) {
int t0, t1, t2, t3, t4;
// apply the InvHaar8 to all columns
#define COMPENSATE(x) (x)
for (int i = 0; i < 4; i++) {
if (flags[i]) {
INV_HAAR4(in[0], in[4], in[8], in[12],
out[0 * pitch], out[1 * pitch],
out[2 * pitch], out[3 * pitch],
t0, t1, t2, t3, t4);
} else {
out[0 * pitch] = out[1 * pitch] =
out[2 * pitch] = out[3 * pitch] = 0;
}
in++;
out++;
}
#undef COMPENSATE
}
void IndeoDSP::ffIviDcHaar2d(const int32 *in, int16 *out, uint32 pitch,
int blkSize) {
int16 dcCoeff = (*in + 0) >> 3;
for (int y = 0; y < blkSize; out += pitch, y++) {
for (int x = 0; x < blkSize; x++)
out[x] = dcCoeff;
}
}
//* butterfly operation for the inverse slant transform
#define IVI_SLANT_BFLY(s1, s2, o1, o2, t) \
t = (s1) - (s2);\
o1 = (s1) + (s2);\
o2 = (t);\
//* This is a reflection a,b = 1/2, 5/4 for the inverse slant transform
#define IVI_IREFLECT(s1, s2, o1, o2, t) \
t = (((s1) + (s2)*2 + 2) >> 2) + (s1);\
o2 = (((s1)*2 - (s2) + 2) >> 2) - (s2);\
o1 = (t);\
//* This is a reflection a,b = 1/2, 7/8 for the inverse slant transform
#define IVI_SLANT_PART4(s1, s2, o1, o2, t) \
t = (s2) + (((s1)*4 - (s2) + 4) >> 3);\
o2 = (s1) + ((-(s1) - (s2)*4 + 4) >> 3);\
o1 = (t);\
//* inverse slant8 transform
#define IVI_INV_SLANT8(s1, s4, s8, s5, s2, s6, s3, s7,\
d1, d2, d3, d4, d5, d6, d7, d8,\
t0, t1, t2, t3, t4, t5, t6, t7, t8) {\
IVI_SLANT_PART4(s4, s5, t4, t5, t0);\
\
IVI_SLANT_BFLY(s1, t5, t1, t5, t0); IVI_SLANT_BFLY(s2, s6, t2, t6, t0);\
IVI_SLANT_BFLY(s7, s3, t7, t3, t0); IVI_SLANT_BFLY(t4, s8, t4, t8, t0);\
\
IVI_SLANT_BFLY(t1, t2, t1, t2, t0); IVI_IREFLECT (t4, t3, t4, t3, t0);\
IVI_SLANT_BFLY(t5, t6, t5, t6, t0); IVI_IREFLECT (t8, t7, t8, t7, t0);\
IVI_SLANT_BFLY(t1, t4, t1, t4, t0); IVI_SLANT_BFLY(t2, t3, t2, t3, t0);\
IVI_SLANT_BFLY(t5, t8, t5, t8, t0); IVI_SLANT_BFLY(t6, t7, t6, t7, t0);\
d1 = COMPENSATE(t1);\
d2 = COMPENSATE(t2);\
d3 = COMPENSATE(t3);\
d4 = COMPENSATE(t4);\
d5 = COMPENSATE(t5);\
d6 = COMPENSATE(t6);\
d7 = COMPENSATE(t7);\
d8 = COMPENSATE(t8);}
//* inverse slant4 transform
#define IVI_INV_SLANT4(s1, s4, s2, s3, d1, d2, d3, d4, t0, t1, t2, t3, t4) {\
IVI_SLANT_BFLY(s1, s2, t1, t2, t0); IVI_IREFLECT (s4, s3, t4, t3, t0);\
\
IVI_SLANT_BFLY(t1, t4, t1, t4, t0); IVI_SLANT_BFLY(t2, t3, t2, t3, t0);\
d1 = COMPENSATE(t1);\
d2 = COMPENSATE(t2);\
d3 = COMPENSATE(t3);\
d4 = COMPENSATE(t4);}
void IndeoDSP::ffIviInverseSlant8x8(const int32 *in, int16 *out, uint32 pitch, const uint8 *flags) {
int32 tmp[64];
int t0, t1, t2, t3, t4, t5, t6, t7, t8;
#define COMPENSATE(x) (x)
const int32 *src = in;
int32 *dst = tmp;
for (int i = 0; i < 8; i++) {
if (flags[i]) {
IVI_INV_SLANT8(src[0], src[8], src[16], src[24], src[32], src[40], src[48], src[56],
dst[0], dst[8], dst[16], dst[24], dst[32], dst[40], dst[48], dst[56],
t0, t1, t2, t3, t4, t5, t6, t7, t8);
} else {
dst[0] = dst[8] = dst[16] = dst[24] = dst[32] = dst[40] = dst[48] = dst[56] = 0;
}
src++;
dst++;
}
#undef COMPENSATE
#define COMPENSATE(x) (((x) + 1)>>1)
src = tmp;
for (int i = 0; i < 8; i++) {
if (!src[0] && !src[1] && !src[2] && !src[3] && !src[4] && !src[5] && !src[6] && !src[7]) {
memset(out, 0, 8*sizeof(out[0]));
} else {
IVI_INV_SLANT8(src[0], src[1], src[2], src[3], src[4], src[5], src[6], src[7],
out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7],
t0, t1, t2, t3, t4, t5, t6, t7, t8);
}
src += 8;
out += pitch;
}
#undef COMPENSATE
}
void IndeoDSP::ffIviInverseSlant4x4(const int32 *in, int16 *out, uint32 pitch, const uint8 *flags) {
int32 tmp[16];
int t0, t1, t2, t3, t4;
#define COMPENSATE(x) (x)
const int32 *src = in;
int32 *dst = tmp;
for (int i = 0; i < 4; i++) {
if (flags[i]) {
IVI_INV_SLANT4(src[0], src[4], src[8], src[12],
dst[0], dst[4], dst[8], dst[12],
t0, t1, t2, t3, t4);
} else {
dst[0] = dst[4] = dst[8] = dst[12] = 0;
}
src++;
dst++;
}
#undef COMPENSATE
#define COMPENSATE(x) (((x) + 1)>>1)
src = tmp;
for (int i = 0; i < 4; i++) {
if (!src[0] && !src[1] && !src[2] && !src[3]) {
out[0] = out[1] = out[2] = out[3] = 0;
} else {
IVI_INV_SLANT4(src[0], src[1], src[2], src[3],
out[0], out[1], out[2], out[3],
t0, t1, t2, t3, t4);
}
src += 4;
out += pitch;
}
#undef COMPENSATE
}
void IndeoDSP::ffIviDcSlant2d(const int32 *in, int16 *out, uint32 pitch,
int blkSize) {
int16 dcCoeff = (*in + 1) >> 1;
for (int y = 0; y < blkSize; out += pitch, y++) {
for (int x = 0; x < blkSize; x++)
out[x] = dcCoeff;
}
}
void IndeoDSP::ffIviRowSlant8(const int32 *in, int16 *out, uint32 pitch,
const uint8 *flags) {
int t0, t1, t2, t3, t4, t5, t6, t7, t8;
#define COMPENSATE(x) (((x) + 1)>>1)
for (int i = 0; i < 8; i++) {
if (!in[0] && !in[1] && !in[2] && !in[3] && !in[4] && !in[5] && !in[6] && !in[7]) {
memset(out, 0, 8*sizeof(out[0]));
} else {
IVI_INV_SLANT8( in[0], in[1], in[2], in[3], in[4], in[5], in[6], in[7],
out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7],
t0, t1, t2, t3, t4, t5, t6, t7, t8);
}
in += 8;
out += pitch;
}
#undef COMPENSATE
}
void IndeoDSP::ffIviDcRowSlant(const int32 *in, int16 *out, uint32 pitch, int blkSize) {
int16 dcCoeff = (*in + 1) >> 1;
for (int x = 0; x < blkSize; x++)
out[x] = dcCoeff;
out += pitch;
for (int y = 1; y < blkSize; out += pitch, y++) {
for (int x = 0; x < blkSize; x++)
out[x] = 0;
}
}
void IndeoDSP::ffIviColSlant8(const int32 *in, int16 *out, uint32 pitch, const uint8 *flags) {
int t0, t1, t2, t3, t4, t5, t6, t7, t8;
int row2 = pitch << 1;
int row4 = pitch << 2;
int row8 = pitch << 3;
#define COMPENSATE(x) (((x) + 1)>>1)
for (int i = 0; i < 8; i++) {
if (flags[i]) {
IVI_INV_SLANT8(in[0], in[8], in[16], in[24], in[32], in[40], in[48], in[56],
out[0], out[pitch], out[row2], out[row2 + pitch], out[row4],
out[row4 + pitch], out[row4 + row2], out[row8 - pitch],
t0, t1, t2, t3, t4, t5, t6, t7, t8);
} else {
out[0] = out[pitch] = out[row2] = out[row2 + pitch] = out[row4] =
out[row4 + pitch] = out[row4 + row2] = out[row8 - pitch] = 0;
}
in++;
out++;
}
#undef COMPENSATE
}
void IndeoDSP::ffIviDcColSlant(const int32 *in, int16 *out, uint32 pitch, int blkSize) {
int16 dcCoeff = (*in + 1) >> 1;
for (int y = 0; y < blkSize; out += pitch, y++) {
out[0] = dcCoeff;
for (int x = 1; x < blkSize; x++)
out[x] = 0;
}
}
void IndeoDSP::ffIviRowSlant4(const int32 *in, int16 *out,
uint32 pitch, const uint8 *flags) {
int t0, t1, t2, t3, t4;
#define COMPENSATE(x) (((x) + 1)>>1)
for (int i = 0; i < 4; i++) {
if (!in[0] && !in[1] && !in[2] && !in[3]) {
memset(out, 0, 4*sizeof(out[0]));
} else {
IVI_INV_SLANT4( in[0], in[1], in[2], in[3],
out[0], out[1], out[2], out[3],
t0, t1, t2, t3, t4);
}
in += 4;
out += pitch;
}
#undef COMPENSATE
}
void IndeoDSP::ffIviColSlant4(const int32 *in, int16 *out, uint32 pitch,
const uint8 *flags) {
int t0, t1, t2, t3, t4;
int row2 = pitch << 1;
#define COMPENSATE(x) (((x) + 1)>>1)
for (int i = 0; i < 4; i++) {
if (flags[i]) {
IVI_INV_SLANT4(in[0], in[4], in[8], in[12],
out[0], out[pitch], out[row2], out[row2 + pitch],
t0, t1, t2, t3, t4);
} else {
out[0] = out[pitch] = out[row2] = out[row2 + pitch] = 0;
}
in++;
out++;
}
#undef COMPENSATE
}
void IndeoDSP::ffIviPutPixels8x8(const int32 *in, int16 *out, uint32 pitch,
const uint8 *flags) {
for (int y = 0; y < 8; out += pitch, in += 8, y++)
for (int x = 0; x < 8; x++)
out[x] = in[x];
}
void IndeoDSP::ffIviPutDcPixel8x8(const int32 *in, int16 *out, uint32 pitch,
int blkSize) {
out[0] = in[0];
memset(out + 1, 0, 7 * sizeof(out[0]));
out += pitch;
for (int y = 1; y < 8; out += pitch, y++)
memset(out, 0, 8 * sizeof(out[0]));
}
#define IVI_MC_TEMPLATE(size, suffix, OP) \
static void iviMc ## size ##x## size ## suffix(int16 *buf, \
uint32 dpitch, \
const int16 *refBuf, \
uint32 pitch, int mcType) \
{ \
const int16 *wptr; \
\
switch (mcType) { \
case 0: /* fullpel (no interpolation) */ \
for (int i = 0; i < size; i++, buf += dpitch, refBuf += pitch) { \
for (int j = 0; j < size; j++) {\
OP(buf[j], refBuf[j]); \
} \
} \
break; \
case 1: /* horizontal halfpel interpolation */ \
for (int i = 0; i < size; i++, buf += dpitch, refBuf += pitch) \
for (int j = 0; j < size; j++) \
OP(buf[j], (refBuf[j] + refBuf[j+1]) >> 1); \
break; \
case 2: /* vertical halfpel interpolation */ \
wptr = refBuf + pitch; \
for (int i = 0; i < size; i++, buf += dpitch, wptr += pitch, refBuf += pitch) \
for (int j = 0; j < size; j++) \
OP(buf[j], (refBuf[j] + wptr[j]) >> 1); \
break; \
case 3: /* vertical and horizontal halfpel interpolation */ \
wptr = refBuf + pitch; \
for (int i = 0; i < size; i++, buf += dpitch, wptr += pitch, refBuf += pitch) \
for (int j = 0; j < size; j++) \
OP(buf[j], (refBuf[j] + refBuf[j+1] + wptr[j] + wptr[j+1]) >> 2); \
break; \
default: \
break; \
} \
} \
\
void IndeoDSP::ffIviMc ## size ##x## size ## suffix(int16 *buf, const int16 *refBuf, \
uint32 pitch, int mcType) \
{ \
iviMc ## size ##x## size ## suffix(buf, pitch, refBuf, pitch, mcType); \
}
#define IVI_MC_AVG_TEMPLATE(size, suffix, OP) \
void IndeoDSP::ffIviMcAvg ## size ##x## size ## suffix(int16 *buf, \
const int16 *refBuf, \
const int16 *refBuf2, \
uint32 pitch, \
int mcType, int mcType2) \
{ \
int16 tmp[size * size]; \
\
iviMc ## size ##x## size ## NoDelta(tmp, size, refBuf, pitch, mcType); \
iviMc ## size ##x## size ## Delta(tmp, size, refBuf2, pitch, mcType2); \
for (int i = 0; i < size; i++, buf += pitch) { \
for (int j = 0; j < size; j++) {\
OP(buf[j], tmp[i * size + j] >> 1); \
} \
} \
}
#define OP_PUT(a, b) (a) = (b)
#define OP_ADD(a, b) (a) += (b)
IVI_MC_TEMPLATE(8, NoDelta, OP_PUT)
IVI_MC_TEMPLATE(8, Delta, OP_ADD)
IVI_MC_TEMPLATE(4, NoDelta, OP_PUT)
IVI_MC_TEMPLATE(4, Delta, OP_ADD)
IVI_MC_AVG_TEMPLATE(8, NoDelta, OP_PUT)
IVI_MC_AVG_TEMPLATE(8, Delta, OP_ADD)
IVI_MC_AVG_TEMPLATE(4, NoDelta, OP_PUT)
IVI_MC_AVG_TEMPLATE(4, Delta, OP_ADD)
} // End of namespace Indeo
} // End of namespace Image

View File

@@ -0,0 +1,335 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/* VLC code
*
* Original copyright note:
* DSP functions (inverse transforms, motion compensation, wavelet recompositions)
* for Indeo Video Interactive codecs.
*/
#ifndef IMAGE_CODECS_INDEO_INDEO_DSP_H
#define IMAGE_CODECS_INDEO_INDEO_DSP_H
#include "image/codecs/indeo/mem.h"
#include "image/codecs/indeo/indeo.h"
namespace Image {
namespace Indeo {
class IndeoDSP {
public:
/**
* two-dimensional inverse Haar 8x8 transform for Indeo 4
*
* @param[in] in Pointer to the vector of transform coefficients
* @param[out] out Pointer to the output buffer (frame)
* @param[in] pitch Pitch to move to the next y line
* @param[in] flags Pointer to the array of column flags:
* != 0 - non_empty column, 0 - empty one
* (this array must be filled by caller)
*/
static void ffIviInverseHaar8x8(const int32 *in, int16 *out, uint32 pitch,
const uint8 *flags);
static void ffIviInverseHaar8x1(const int32 *in, int16 *out, uint32 pitch,
const uint8 *flags);
static void ffIviInverseHaar1x8(const int32 *in, int16 *out, uint32 pitch,
const uint8 *flags);
/**
* one-dimensional inverse 8-point Haar transform on rows for Indeo 4
*
* @param[in] in Pointer to the vector of transform coefficients
* @param[out] out Pointer to the output buffer (frame)
* @param[in] pitch Pitch to move to the next y line
* @param[in] flags Pointer to the array of column flags:
* != 0 - non_empty column, 0 - empty one
* (this array must be filled by caller)
*/
static void ffIviRowHaar8(const int32 *in, int16 *out, uint32 pitch,
const uint8 *flags);
/**
* one-dimensional inverse 8-point Haar transform on columns for Indeo 4
*
* @param[in] in Pointer to the vector of transform coefficients
* @param[out] out Pointer to the output buffer (frame)
* @param[in] pitch Pitch to move to the next y line
* @param[in] flags Pointer to the array of column flags:
* != 0 - non_empty column, 0 - empty one
* (this array must be filled by caller)
*/
static void ffIviColHaar8(const int32 *in, int16 *out, uint32 pitch,
const uint8 *flags);
/**
* two-dimensional inverse Haar 4x4 transform for Indeo 4
*
* @param[in] in Pointer to the vector of transform coefficients
* @param[out] out Pointer to the output buffer (frame)
* @param[in] pitch Pitch to move to the next y line
* @param[in] flags Pointer to the array of column flags:
* != 0 - non_empty column, 0 - empty one
* (this array must be filled by caller)
*/
static void ffIviInverseHaar4x4(const int32 *in, int16 *out, uint32 pitch,
const uint8 *flags);
/**
* one-dimensional inverse 4-point Haar transform on rows for Indeo 4
*
* @param[in] in Pointer to the vector of transform coefficients
* @param[out] out Pointer to the output buffer (frame)
* @param[in] pitch Pitch to move to the next y line
* @param[in] flags Pointer to the array of column flags:
* != 0 - non_empty column, 0 - empty one
* (this array must be filled by caller)
*/
static void ffIviRowHaar4(const int32 *in, int16 *out, uint32 pitch,
const uint8 *flags);
/**
* one-dimensional inverse 4-point Haar transform on columns for Indeo 4
*
* @param[in] in Pointer to the vector of transform coefficients
* @param[out] out Pointer to the output buffer (frame)
* @param[in] pitch Pitch to move to the next y line
* @param[in] flags Pointer to the array of column flags:
* != 0 - non_empty column, 0 - empty one
* (this array must be filled by caller)
*/
static void ffIviColHaar4(const int32 *in, int16 *out, uint32 pitch,
const uint8 *flags);
/**
* DC-only two-dimensional inverse Haar transform for Indeo 4.
* Performing the inverse transform in this case is equivalent to
* spreading dcCoeff >> 3 over the whole block.
*
* @param[in] in Pointer to the dc coefficient
* @param[out] out Pointer to the output buffer (frame)
* @param[in] pitch Pitch to move to the next y line
* @param[in] blkSize Transform block size
*/
static void ffIviDcHaar2d(const int32 *in, int16 *out, uint32 pitch,
int blkSize);
/**
* two-dimensional inverse slant 8x8 transform
*
* @param[in] in Pointer to the vector of transform coefficients
* @param[out] out Pointer to the output buffer (frame)
* @param[in] pitch Pitch to move to the next y line
* @param[in] flags Pointer to the array of column flags:
* != 0 - non_empty column, 0 - empty one
* (this array must be filled by caller)
*/
static void ffIviInverseSlant8x8(const int32 *in, int16 *out, uint32 pitch,
const uint8 *flags);
/**
* two-dimensional inverse slant 4x4 transform
*
* @param[in] in Pointer to the vector of transform coefficients
* @param[out] out Pointer to the output buffer (frame)
* @param[in] pitch Pitch to move to the next y line
* @param[in] flags Pointer to the array of column flags:
* != 0 - non_empty column, 0 - empty one
* (this array must be filled by caller)
*/
static void ffIviInverseSlant4x4(const int32 *in, int16 *out, uint32 pitch,
const uint8 *flags);
/**
* DC-only two-dimensional inverse slant transform.
* Performing the inverse slant transform in this case is equivalent to
* spreading (dcCoeff + 1)/2 over the whole block.
* It works much faster than performing the slant transform on a vector of zeroes.
*
* @param[in] in Pointer to the dc coefficient
* @param[out] out Pointer to the output buffer (frame)
* @param[in] pitch Pitch to move to the next y line
* @param[in] blkSize Transform block size
*/
static void ffIviDcSlant2d(const int32 *in, int16 *out, uint32 pitch, int blkSize);
/**
* inverse 1D row slant transform
*
* @param[in] in Pointer to the vector of transform coefficients
* @param[out] out Pointer to the output buffer (frame)
* @param[in] pitch Pitch to move to the next y line
* @param[in] flags Pointer to the array of column flags (unused here)
*/
static void ffIviRowSlant8(const int32 *in, int16 *out, uint32 pitch,
const uint8 *flags);
/**
* inverse 1D column slant transform
*
* @param[in] in Pointer to the vector of transform coefficients
* @param[out] out Pointer to the output buffer (frame)
* @param[in] pitch Pitch to move to the next y line
* @param[in] flags Pointer to the array of column flags:
* != 0 - non_empty column, 0 - empty one
* (this array must be filled by caller)
*/
static void ffIviColSlant8(const int32 *in, int16 *out, uint32 pitch,
const uint8 *flags);
/**
* inverse 1D row slant transform
*
* @param[in] in Pointer to the vector of transform coefficients
* @param[out] out Pointer to the output buffer (frame)
* @param[in] pitch Pitch to move to the next y line
* @param[in] flags Pointer to the array of column flags (unused here)
*/
static void ffIviRowSlant4(const int32 *in, int16 *out, uint32 pitch,
const uint8 *flags);
/**
* inverse 1D column slant transform
*
* @param[in] in Pointer to the vector of transform coefficients
* @param[out] out Pointer to the output buffer (frame)
* @param[in] pitch Pitch to move to the next y line
* @param[in] flags Pointer to the array of column flags:
* != 0 - non_empty column, 0 - empty one
* (this array must be filled by caller)
*/
static void ffIviColSlant4(const int32 *in, int16 *out, uint32 pitch,
const uint8 *flags);
/**
* DC-only inverse row slant transform
*/
static void ffIviDcRowSlant(const int32 *in, int16 *out, uint32 pitch, int blkSize);
/**
* DC-only inverse column slant transform
*/
static void ffIviDcColSlant(const int32 *in, int16 *out, uint32 pitch, int blkSize);
/**
* Copy the pixels into the frame buffer.
*/
static void ffIviPutPixels8x8(const int32 *in, int16 *out, uint32 pitch, const uint8 *flags);
/**
* Copy the DC coefficient into the first pixel of the block and
* zero all others.
*/
static void ffIviPutDcPixel8x8(const int32 *in, int16 *out, uint32 pitch, int blkSize);
/**
* 8x8 block motion compensation with adding delta
*
* @param[in,out] buf Pointer to the block in the current frame buffer containing delta
* @param[in] refBuf Pointer to the corresponding block in the reference frame
* @param[in] pitch Pitch for moving to the next y line
* @param[in] mcType Interpolation type
*/
static void ffIviMc8x8Delta(int16 *buf, const int16 *refBuf, uint32 pitch, int mcType);
/**
* 4x4 block motion compensation with adding delta
*
* @param[in,out] buf Pointer to the block in the current frame buffer containing delta
* @param[in] refBuf Pointer to the corresponding block in the reference frame
* @param[in] pitch Pitch for moving to the next y line
* @param[in] mcType Interpolation type
*/
static void ffIviMc4x4Delta(int16 *buf, const int16 *refBuf, uint32 pitch, int mcType);
/**
* motion compensation without adding delta
*
* @param[in,out] buf Pointer to the block in the current frame buffer containing delta
* @param[in] refBuf Pointer to the corresponding block in the reference frame
* @param[in] pitch Pitch for moving to the next y line
* @param[in] mcType Interpolation type
*/
static void ffIviMc8x8NoDelta(int16 *buf, const int16 *refBuf, uint32 pitch, int mcType);
/**
* 4x4 block motion compensation without adding delta
*
* @param[in,out] buf Pointer to the block in the current frame receiving the result
* @param[in] refBuf Pointer to the corresponding block in the reference frame
* @param[in] pitch Pitch for moving to the next y line
* @param[in] mcType Interpolation type
*/
static void ffIviMc4x4NoDelta(int16 *buf, const int16 *refBuf, uint32 pitch, int mcType);
/**
* 8x8 block motion compensation with adding delta
*
* @param[in,out] buf Pointer to the block in the current frame buffer containing delta
* @param[in] refBuf Pointer to the corresponding block in the backward reference frame
* @param[in] refBuf2 Pointer to the corresponding block in the forward reference frame
* @param[in] pitch Pitch for moving to the next y line
* @param[in] mcType Interpolation type for backward reference
* @param[in] mcType2 Interpolation type for forward reference
*/
static void ffIviMcAvg8x8Delta(int16 *buf, const int16 *refBuf, const int16 *refBuf2, uint32 pitch, int mcType, int mcType2);
/**
* 4x4 block motion compensation with adding delta
*
* @param[in,out] buf Pointer to the block in the current frame buffer containing delta
* @param[in] refBuf Pointer to the corresponding block in the backward reference frame
* @param[in] refBuf2 Pointer to the corresponding block in the forward reference frame
* @param[in] pitch Pitch for moving to the next y line
* @param[in] mcType Interpolation type for backward reference
* @param[in] mcType2 Interpolation type for forward reference
*/
static void ffIviMcAvg4x4Delta(int16 *buf, const int16 *refBuf, const int16 *refBuf2, uint32 pitch, int mcType, int mcType2);
/**
* motion compensation without adding delta for B-frames
*
* @param[in,out] buf Pointer to the block in the current frame buffer containing delta
* @param[in] refBuf Pointer to the corresponding block in the backward reference frame
* @param[in] refBuf2 Pointer to the corresponding block in the forward reference frame
* @param[in] pitch Pitch for moving to the next y line
* @param[in] mcType Interpolation type for backward reference
* @param[in] mcType2 Interpolation type for forward reference
*/
static void ffIviMcAvg8x8NoDelta(int16 *buf, const int16 *refBuf, const int16 *refBuf2, uint32 pitch, int mcType, int mcType2);
/**
* 4x4 block motion compensation without adding delta for B-frames
*
* @param[in,out] buf Pointer to the block in the current frame buffer containing delta
* @param[in] refBuf Pointer to the corresponding block in the backward reference frame
* @param[in] refBuf2 Pointer to the corresponding block in the forward reference frame
* @param[in] pitch Pitch for moving to the next y line
* @param[in] mcType Interpolation type for backward reference
* @param[in] mcType2 Interpolation type for forward reference
*/
static void ffIviMcAvg4x4NoDelta(int16 *buf, const int16 *refBuf, const int16 *refBuf2, uint32 pitch, int mcType, int mcType2);
};
} // End of namespace Indeo
} // End of namespace Image
#endif

135
image/codecs/indeo/mem.cpp Normal file
View File

@@ -0,0 +1,135 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/* VLC code
*
* Original copyright note: * Intel Indeo 4 (IV41, IV42, etc.) video decoder for ffmpeg
* written, produced, and directed by Alan Smithee
*/
#include "image/codecs/indeo/mem.h"
namespace Image {
namespace Indeo {
const uint8 ffReverse[256] = {
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF,
};
const uint8 ffZigZagDirect[64] = {
0, 1, 8, 16, 9, 2, 3, 10,
17, 24, 32, 25, 18, 11, 4, 5,
12, 19, 26, 33, 40, 48, 41, 34,
27, 20, 13, 6, 7, 14, 21, 28,
35, 42, 49, 56, 57, 50, 43, 36,
29, 22, 15, 23, 30, 37, 44, 51,
58, 59, 52, 45, 38, 31, 39, 46,
53, 60, 61, 54, 47, 55, 62, 63
};
/*------------------------------------------------------------------------*/
/**
* Multiply two `size_t` values checking for overflow.
*
* @param[in] a,b Operands of multiplication
* @param[out] r Pointer to the result of the operation
* @return 0 on success, AVERROR(EINVAL) on overflow
*/
static inline int avSizeMult(size_t a, size_t b, size_t *r) {
size_t t = a * b;
// Hack inspired from glibc: don't try the division if nelem and elsize
// are both less than sqrt(SIZE_MAX).
if ((a | b) >= ((size_t)1 << (sizeof(size_t) * 4)) && a && t / a != b)
return -1;
*r = t;
return 0;
}
/*------------------------------------------------------------------------*/
void avFreeP(void *arg) {
void **ptr = (void **)arg;
free(*ptr);
*ptr = nullptr;
}
void *avReallocF(void *ptr, size_t nelem, size_t elsize) {
size_t size;
void *r;
if (avSizeMult(elsize, nelem, &size)) {
free(ptr);
return nullptr;
}
r = realloc(ptr, size);
if (!r)
free(ptr);
return r;
}
/**
* Swap the order of the bytes in the passed value
*/
uint32 bitswap32(uint32 x) {
return (uint32)ffReverse[x & 0xFF] << 24 |
(uint32)ffReverse[(x >> 8) & 0xFF] << 16 |
(uint32)ffReverse[(x >> 16) & 0xFF] << 8 |
(uint32)ffReverse[x >> 24];
}
/**
* Reverse "nbits" bits of the value "val" and return the result
* in the least significant bits.
*/
uint16 invertBits(uint16 val, int nbits) {
uint16 res;
if (nbits <= 8) {
res = ffReverse[val] >> (8 - nbits);
} else {
res = ((ffReverse[val & 0xFF] << 8) +
(ffReverse[val >> 8])) >> (16 - nbits);
}
return res;
}
} // End of namespace Indeo
} // End of namespace Image

109
image/codecs/indeo/mem.h Normal file
View File

@@ -0,0 +1,109 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/scummsys.h"
/* Common memory code used by the Indeo decoder
*
* Original copyright note: * Intel Indeo 4 (IV41, IV42, etc.) video decoder for ffmpeg
* written, produced, and directed by Alan Smithee
*/
#ifndef IMAGE_CODECS_INDEO_MEM_H
#define IMAGE_CODECS_INDEO_MEM_H
namespace Image {
namespace Indeo {
#define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
#define FFALIGN(x, a) (((x) + (a)-1) & ~((a)-1))
#define FFSIGN(a) ((a) > 0 ? 1 : -1)
#define MAX_INTEGER 0x7ffffff
/**
* Free a memory block which has been allocated with a function of av_malloc()
* or av_realloc() family, and set the pointer pointing to it to `NULL`.
*
* @param ptr Pointer to the pointer to the memory block which should be freed
* @note `*ptr = NULL` is safe and leads to no action.
*/
extern void avFreeP(void *arg);
/**
* Allocate, reallocate, or free a block of memory.
*
* This function does the same thing as av_realloc(), except:
* - It takes two size arguments and allocates `nelem * elsize` bytes,
* after checking the result of the multiplication for integer overflow.
* - It frees the input block in case of failure, thus avoiding the memory
* leak with the classic
* @code{.c}
* buf = realloc(buf);
* if (!buf)
* return -1;
* @endcode
* pattern.
*/
extern void *avReallocF(void *ptr, size_t nelem, size_t elsize);
/**
* Reverse "nbits" bits of the value "val" and return the result
* in the least significant bits.
*/
extern uint16 invertBits(uint16 val, int nbits);
/**
* Swap the order of the bytes in the passed value
*/
extern uint32 bitswap32(uint32 x);
/**
* Clip a signed integer value into the 0-255 range.
* @param a value to clip
* @return clipped value
*/
inline uint8 avClipUint8(int a) {
if (a & (~0xFF))
return (-a) >> 31;
else
return a;
}
/**
* Clip a signed integer to an unsigned power of two range.
* @param a value to clip
* @param p bit position to clip at
* @return clipped value
*/
inline unsigned avClipUintp2(int a, int p) {
if (a & ~((1 << p) - 1))
return -a >> 31 & ((1 << p) - 1);
else
return a;
}
extern const uint8 ffZigZagDirect[64];
} // End of namespace Indeo
} // End of namespace Image
#endif

335
image/codecs/indeo/vlc.cpp Normal file
View File

@@ -0,0 +1,335 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/* VLC code
*
* Original copyright note: * Intel Indeo 4 (IV41, IV42, etc.) video decoder for ffmpeg
* written, produced, and directed by Alan Smithee
*/
#include "image/codecs/indeo/vlc.h"
#include "image/codecs/indeo/mem.h"
#include "common/textconsole.h"
#include "common/util.h"
namespace Image {
namespace Indeo {
/**
* Quicksort
* This sort is fast, and fully inplace but not stable and it is possible
* to construct input that requires O(n^2) time but this is very unlikely to
* happen with non constructed input.
*/
#define AV_QSORT(p, num, type, cmp) do {\
void *stack[64][2];\
int sp = 1;\
stack[0][0] = p;\
stack[0][1] = (p)+(num)-1;\
while(sp){\
type *start = (type *)stack[--sp][0];\
type *end = (type *)stack[ sp][1];\
while (start < end) {\
if (start < end-1) {\
int checksort = 0;\
type *right = end - 2;\
type *left = start + 1;\
type *mid = start + ((end - start) >> 1);\
if(cmp(start, end) > 0) {\
if(cmp( end, mid) > 0) SWAP(*start, *mid);\
else SWAP(*start, *end);\
} else {\
if(cmp(start, mid) > 0) SWAP(*start, *mid);\
else checksort = 1;\
}\
if (cmp(mid, end) > 0) { \
SWAP(*mid, *end);\
checksort = 0;\
}\
if(start == end - 2) break;\
SWAP(end[-1], *mid);\
while (left <= right) {\
while (left<=right && cmp(left, end - 1) < 0)\
left++;\
while (left<=right && cmp(right, end - 1) > 0)\
right--;\
if (left <= right) {\
SWAP(*left, *right);\
left++;\
right--;\
}\
}\
SWAP(end[-1], *left);\
if(checksort && (mid == left - 1 || mid == left)){\
mid= start;\
while(mid<end && cmp(mid, mid+1) <= 0)\
mid++;\
if(mid==end)\
break;\
}\
if (end - left < left - start){\
stack[sp ][0] = start;\
stack[sp++][1] = right;\
start = left + 1;\
} else {\
stack[sp ][0] = left+1;\
stack[sp++][1] = end;\
end = right;\
}\
} else {\
if (cmp(start, end) > 0)\
SWAP(*start, *end);\
break;\
}\
}\
}\
} while (0)
#define COPY(condition)\
for (i = 0; i < nbCodes; i++) { \
buf[j].bits = getData(p_bits, i, bitsWrap, bitsSize); \
if (!(condition)) \
continue; \
if (buf[j].bits > (3 * nbBits) || buf[j].bits > 32) { \
warning("Too long VLC (%d) in init_vlc", buf[j].bits); \
if (!(flags & INIT_VLC_USE_NEW_STATIC)) \
free(buf); \
return -1; \
} \
buf[j].code = getData(codes, i, codesWrap, codesSize); \
if (buf[j].code >= (1LL << buf[j].bits)) { \
warning("Invalid code %x for %d in init_vlc", buf[j].code, i); \
if (!(flags & INIT_VLC_USE_NEW_STATIC)) \
free(buf); \
return -1; \
} \
if (flags & INIT_VLC_LE) \
buf[j].code = bitswap32(buf[j].code); \
else \
buf[j].code <<= 32 - buf[j].bits; \
if (symbols) \
buf[j].symbol = getData(symbols, i, symbolsWrap, symbolsSize); \
else \
buf[j].symbol = i; \
j++; \
}
/*------------------------------------------------------------------------*/
VLC::VLC() : _bits(0), _tableSize(0), _tableAllocated(0), _table(nullptr) {
}
int VLC::init_vlc(int nbBits, int nbCodes, const void *bits, int bitsWrap, int bitsSize,
const void *codes, int codesWrap, int codesSize, int flags) {
return init_vlc(nbBits, nbCodes, bits, bitsWrap, bitsSize, codes, codesWrap,
codesSize, nullptr, 0, 0, flags);
}
int VLC::init_vlc(int nbBits, int nbCodes, const void *p_bits, int bitsWrap,
int bitsSize, const void *codes, int codesWrap, int codesSize,
const void *symbols, int symbolsWrap, int symbolsSize, int flags) {
VLCcode *buf;
int i, j, ret;
VLCcode localbuf[1500]; // the maximum currently needed is 1296 by rv34
VLC localvlc, *vlc;
vlc = this;
vlc->_bits = nbBits;
if (flags & INIT_VLC_USE_NEW_STATIC) {
assert((nbCodes + 1) <= (int)FF_ARRAY_ELEMS(localbuf));
buf = localbuf;
localvlc = *this;
vlc = &localvlc;
vlc->_tableSize = 0;
} else {
vlc->_table = NULL;
vlc->_tableAllocated = 0;
vlc->_tableSize = 0;
buf = (VLCcode *)malloc((nbCodes + 1) * sizeof(VLCcode));
assert(buf);
}
assert(symbolsSize <= 2 || !symbols);
j = 0;
COPY(buf[j].bits > nbBits);
// qsort is the slowest part of init_vlc, and could probably be improved or avoided
AV_QSORT(buf, j, VLCcode, compareVlcSpec);
COPY(buf[j].bits && buf[j].bits <= nbBits);
nbCodes = j;
ret = vlc->buildTable(nbBits, nbCodes, buf, flags);
if (flags & INIT_VLC_USE_NEW_STATIC) {
if (vlc->_tableSize != vlc->_tableAllocated)
warning("needed %d had %d", vlc->_tableSize, vlc->_tableAllocated);
assert(ret >= 0);
*this = *vlc;
} else {
free(buf);
if (ret < 0) {
avFreeP(&vlc->_table);
return -1;
}
}
return 0;
}
void VLC::freeVlc() {
free(_table);
}
int VLC::compareVlcSpec(const void *a, const void *b) {
const VLCcode *sa = (const VLCcode *)a, *sb = (const VLCcode *)b;
return (sa->code >> 1) - (sb->code >> 1);
}
int VLC::buildTable(int tableNbBits, int nbCodes,
VLCcode *codes, int flags) {
VLC *vlc = this;
int tableSize, tableIndex, index, codePrefix, symbol, subtableBits;
int i, j, k, n, nb, inc;
uint32 code;
VLC_TYPE (*table)[2];
tableSize = 1 << tableNbBits;
if (tableNbBits > 30)
return -1;
tableIndex = allocTable(tableSize, flags & INIT_VLC_USE_NEW_STATIC);
//warning("new table index=%d size=%d", tableIndex, tableSize);
if (tableIndex < 0)
return tableIndex;
table = &vlc->_table[tableIndex];
// first pass: map codes and compute auxiliary table sizes
for (i = 0; i < nbCodes; i++) {
n = codes[i].bits;
code = codes[i].code;
symbol = codes[i].symbol;
//warning("i=%d n=%d code=0x%x", i, n, code);
if (n <= tableNbBits) {
// no need to add another table
j = code >> (32 - tableNbBits);
nb = 1 << (tableNbBits - n);
inc = 1;
if (flags & INIT_VLC_LE) {
j = bitswap32(code);
inc = 1 << n;
}
for (k = 0; k < nb; k++) {
int bits = table[j][1];
//warning("%4x: code=%d n=%d", j, i, n);
if (bits != 0 && bits != n) {
warning("incorrect codes");
return -1;
}
table[j][1] = n; //bits
table[j][0] = symbol;
j += inc;
}
} else {
// fill auxiliary table recursively
n -= tableNbBits;
codePrefix = code >> (32 - tableNbBits);
subtableBits = n;
codes[i].bits = n;
codes[i].code = code << tableNbBits;
for (k = i + 1; k < nbCodes; k++) {
n = codes[k].bits - tableNbBits;
if (n <= 0)
break;
code = codes[k].code;
if (code >> (32 - tableNbBits) != (uint)codePrefix)
break;
codes[k].bits = n;
codes[k].code = code << tableNbBits;
subtableBits = MAX(subtableBits, n);
}
subtableBits = MIN(subtableBits, tableNbBits);
j = (flags & INIT_VLC_LE) ? bitswap32(codePrefix) >> (32 - tableNbBits) : codePrefix;
table[j][1] = -subtableBits;
//warning("%4x: n=%d (subtable)", j, codes[i].bits + tableNbBits);
index = vlc->buildTable(subtableBits, k - i, codes + i, flags);
if (index < 0)
return index;
// note: realloc has been done, so reload tables
table = (VLC_TYPE (*)[2])&vlc->_table[tableIndex];
table[j][0] = index; //code
i = k - 1;
}
}
for (i = 0; i < tableSize; i++) {
if (table[i][1] == 0) //bits
table[i][0] = -1; //codes
}
return tableIndex;
}
int VLC::allocTable(int size, int useStatic) {
VLC *vlc = this;
int index = vlc->_tableSize;
vlc->_tableSize += size;
if (vlc->_tableSize > vlc->_tableAllocated) {
// cannot do anything, init_vlc() is used with too little memory
assert(!useStatic);
vlc->_tableAllocated += (1 << vlc->_bits);
vlc->_table = (int16(*)[2])avReallocF(vlc->_table, vlc->_tableAllocated, sizeof(VLC_TYPE) * 2);
if (!vlc->_table) {
vlc->_tableAllocated = 0;
vlc->_tableSize = 0;
return -2;
}
memset(vlc->_table + vlc->_tableAllocated - (static_cast<ptrdiff_t>(1) << vlc->_bits), 0, sizeof(VLC_TYPE) * 2 << vlc->_bits);
}
return index;
}
uint VLC::getData(const void *table, uint idx, uint wrap, uint size) {
const uint8 *ptr = (const uint8 *)table + idx * wrap;
switch(size) {
case 1:
return *(const uint8 *)ptr;
case 2:
return *(const uint16 *)ptr;
default:
return *(const uint32 *)ptr;
}
}
} // End of namespace Indeo
} // End of namespace Image

134
image/codecs/indeo/vlc.h Normal file
View File

@@ -0,0 +1,134 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/scummsys.h"
/* VLC code
*
* Original copyright note: * Intel Indeo 4 (IV41, IV42, etc.) video decoder for ffmpeg
* written, produced, and directed by Alan Smithee
*/
#ifndef IMAGE_CODECS_INDEO_VLC_H
#define IMAGE_CODECS_INDEO_VLC_H
#include "image/codecs/indeo/get_bits.h"
namespace Image {
namespace Indeo {
#define VLC_TYPE int16
enum VLCFlag {
INIT_VLC_LE = 2,
INIT_VLC_USE_NEW_STATIC = 4
};
struct VLCcode {
uint8 bits;
uint16 symbol;
/**
* codeword, with the first bit-to-be-read in the msb
* (even if intended for a little-endian bitstream reader)
*/
uint32 code;
};
struct VLC {
private:
static int compareVlcSpec(const void *a, const void *b);
/**
* Gets a value of a given size from a table
* @param table Table to get data from
* @param idx Index of value to retrieve
* @param wrap Size of elements with alignment
* @param size Size of elements
*/
static uint getData(const void *table, uint idx, uint wrap, uint size);
public:
int _bits;
VLC_TYPE (*_table)[2]; ///< code, bits
int _tableSize, _tableAllocated;
VLC();
/* Build VLC decoding tables suitable for use with get_vlc().
'nbBits' sets the decoding table size (2^nbBits) entries. The
bigger it is, the faster is the decoding. But it should not be too
big to save memory and L1 cache. '9' is a good compromise.
'nbCodes' : number of vlcs codes
'bits' : table which gives the size (in bits) of each vlc code.
'codes' : table which gives the bit pattern of of each vlc code.
'symbols' : table which gives the values to be returned from get_vlc().
'xxx_wrap' : give the number of bytes between each entry of the
'bits' or 'codes' tables.
'xxx_size' : gives the number of bytes of each entry of the 'bits'
or 'codes' tables.
'wrap' and 'size' make it possible to use any memory configuration and types
(byte/word/long) to store the 'bits', 'codes', and 'symbols' tables.
'useStatic' should be set to 1 for tables, which should be freed
with av_free_static(), 0 if freeVlc() will be used.
*/
int init_vlc(int nbBits, int nbCodes, const void *bits, int bitsWrap,
int bitsSize, const void *codes, int codesWrap, int codesSize,
const void *symbols, int symbolsWrap, int symbolsSize, int flags);
int init_vlc(int nbBits, int nbCodes, const void *bits, int bitsWrap, int bitsSize,
const void *codes, int codesWrap, int codesSize, int flags);
/**
* Free VLC data
*/
void freeVlc();
/**
* Build VLC decoding tables suitable for use with get_vlc().
*
* @param tableNbBits max length of vlc codes to store directly in this table
* (Longer codes are delegated to subtables.)
*
* @param nbCodes number of elements in codes[]
*
* @param codes descriptions of the vlc codes
* These must be ordered such that codes going into the same subtable are contiguous.
* Sorting by VLCcode.code is sufficient, though not necessary.
*/
int buildTable(int tableNbBits, int nbCodes, VLCcode *codes, int flags);
int allocTable(int size, int useStatic);
};
} // End of namespace Indeo
} // End of namespace Image
#endif