aboutsummaryrefslogtreecommitdiff
path: root/image
diff options
context:
space:
mode:
Diffstat (limited to 'image')
-rw-r--r--image/codecs/codec.cpp7
-rw-r--r--image/codecs/indeo/get_bits.cpp60
-rw-r--r--image/codecs/indeo/get_bits.h63
-rw-r--r--image/codecs/indeo/indeo.cpp1729
-rw-r--r--image/codecs/indeo/indeo.h584
-rw-r--r--image/codecs/indeo/indeo_dsp.cpp644
-rw-r--r--image/codecs/indeo/indeo_dsp.h336
-rw-r--r--image/codecs/indeo/mem.cpp172
-rw-r--r--image/codecs/indeo/mem.h148
-rw-r--r--image/codecs/indeo/vlc.cpp336
-rw-r--r--image/codecs/indeo/vlc.h135
-rw-r--r--image/codecs/indeo4.cpp951
-rw-r--r--image/codecs/indeo4.h140
-rw-r--r--image/codecs/indeo5.cpp744
-rw-r--r--image/codecs/indeo5.h136
-rw-r--r--image/module.mk9
16 files changed, 6193 insertions, 1 deletions
diff --git a/image/codecs/codec.cpp b/image/codecs/codec.cpp
index 9e5c1bfe08..913b7afab3 100644
--- a/image/codecs/codec.cpp
+++ b/image/codecs/codec.cpp
@@ -30,6 +30,8 @@
#include "image/codecs/cdtoons.h"
#include "image/codecs/cinepak.h"
#include "image/codecs/indeo3.h"
+#include "image/codecs/indeo4.h"
+#include "image/codecs/indeo5.h"
#include "image/codecs/mjpeg.h"
#include "image/codecs/mpeg.h"
#include "image/codecs/msvideo1.h"
@@ -209,6 +211,11 @@ 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);
+ case MKTAG('I', 'V', '5', '0'):
+ return new Indeo5Decoder(width, height);
#ifdef IMAGE_CODECS_TRUEMOTION1_H
case MKTAG('D','U','C','K'):
case MKTAG('d','u','c','k'):
diff --git a/image/codecs/indeo/get_bits.cpp b/image/codecs/indeo/get_bits.cpp
new file mode 100644
index 0000000000..f808a96e76
--- /dev/null
+++ b/image/codecs/indeo/get_bits.cpp
@@ -0,0 +1,60 @@
+/* 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"
+
+namespace Image {
+namespace Indeo {
+
+int GetBits::getVLC2(int16 (*table)[2], int bits, int maxDepth) {
+ 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
diff --git a/image/codecs/indeo/get_bits.h b/image/codecs/indeo/get_bits.h
new file mode 100644
index 0000000000..359d8fcab0
--- /dev/null
+++ b/image/codecs/indeo/get_bits.h
@@ -0,0 +1,63 @@
+/* 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.
+ *
+ */
+
+#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::BitStream8LSB {
+public:
+ /**
+ * Constructor
+ * @param stream Source stream to reader from
+ * @param disposeAfterUse Whether to destroy stream in destructor
+ */
+ GetBits(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse
+ = DisposeAfterUse::YES) : Common::BitStream8LSB(stream, disposeAfterUse) {}
+
+ /**
+ * 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
+ */
+ int getVLC2(int16 (*table)[2], int bits, int maxDepth);
+};
+
+} // End of namespace Indeo
+} // End of namespace Image
+
+#endif
diff --git a/image/codecs/indeo/indeo.cpp b/image/codecs/indeo/indeo.cpp
new file mode 100644
index 0000000000..2bc699ecf5
--- /dev/null
+++ b/image/codecs/indeo/indeo.cpp
@@ -0,0 +1,1729 @@
+/* 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.
+ *
+ */
+
+/* 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
+ */
+
+#include "image/codecs/indeo/indeo.h"
+#include "image/codecs/indeo/indeo_dsp.h"
+#include "image/codecs/indeo/mem.h"
+#include "graphics/yuv_to_rgb.h"
+#include "common/system.h"
+#include "common/algorithm.h"
+#include "common/textconsole.h"
+#include "common/util.h"
+
+namespace Image {
+namespace Indeo {
+
+/**
+ * These are 2x8 predefined Huffman codebooks for coding macroblock/block
+ * signals. They are specified using "huffman descriptors" in order to
+ * avoid huge static tables. The decoding tables will be generated at
+ * startup from these descriptors.
+ */
+
+/**
+ * Static macroblock huffman tables
+ */
+static const IVIHuffDesc ivi_mb_huff_desc[8] = {
+ {8, {0, 4, 5, 4, 4, 4, 6, 6}},
+ {12, {0, 2, 2, 3, 3, 3, 3, 5, 3, 2, 2, 2}},
+ {12, {0, 2, 3, 4, 3, 3, 3, 3, 4, 3, 2, 2}},
+ {12, {0, 3, 4, 4, 3, 3, 3, 3, 3, 2, 2, 2}},
+ {13, {0, 4, 4, 3, 3, 3, 3, 2, 3, 3, 2, 1, 1}},
+ {9, {0, 4, 4, 4, 4, 3, 3, 3, 2}},
+ {10, {0, 4, 4, 4, 4, 3, 3, 2, 2, 2}},
+ {12, {0, 4, 4, 4, 3, 3, 2, 3, 2, 2, 2, 2}}
+};
+
+/**
+ * static block huffman tables
+ */
+static const IVIHuffDesc ivi_blk_huff_desc[8] = {
+ {10, {1, 2, 3, 4, 4, 7, 5, 5, 4, 1} },
+ {11, {2, 3, 4, 4, 4, 7, 5, 4, 3, 3, 2} },
+ {12, {2, 4, 5, 5, 5, 5, 6, 4, 4, 3, 1, 1} },
+ {13, {3, 3, 4, 4, 5, 6, 6, 4, 4, 3, 2, 1, 1} },
+ {11, {3, 4, 4, 5, 5, 5, 6, 5, 4, 2, 2} },
+ {13, {3, 4, 5, 5, 5, 5, 6, 4, 3, 3, 2, 1, 1} },
+ {13, {3, 4, 5, 5, 5, 6, 5, 4, 3, 3, 2, 1, 1} },
+ {9, {3, 4, 4, 5, 5, 5, 6, 5, 5} }
+};
+
+/*------------------------------------------------------------------------*/
+
+/**
+ * calculate number of _tiles in a stride
+ */
+#define IVI_NUM_TILES(stride, tileSize) (((stride) + (tileSize) - 1) / (tileSize))
+
+/*------------------------------------------------------------------------*/
+
+int IVIHuffDesc::createHuffFromDesc(VLC *vlc, bool flag) const {
+ int pos, i, j, codesPerRow, prefix, notLastRow;
+ uint16 codewords[256];
+ uint8 bits[256];
+
+ pos = 0; // current position = 0
+
+ for (i = 0; i < _numRows; i++) {
+ codesPerRow = 1 << _xBits[i];
+ notLastRow = (i != _numRows - 1);
+ prefix = ((1 << i) - 1) << (_xBits[i] + notLastRow);
+
+ for (j = 0; j < codesPerRow; j++) {
+ if (pos >= 256) // Some Indeo5 codebooks can have more than 256
+ break; // elements, but only 256 codes are allowed!
+
+ bits[pos] = i + _xBits[i] + notLastRow;
+ if (bits[pos] > IVI_VLC_BITS)
+ return -1; // invalid descriptor
+
+ codewords[pos] = invertBits((prefix | j), bits[pos]);
+ if (!bits[pos])
+ bits[pos] = 1;
+
+ pos++;
+ }//for j
+ }//for i
+
+ // number of codewords = pos
+ return vlc->init_vlc(IVI_VLC_BITS, pos, bits, 1, 1, codewords, 2, 2,
+ (flag ? INIT_VLC_USE_NEW_STATIC : 0) | INIT_VLC_LE);
+}
+
+/*------------------------------------------------------------------------*/
+
+bool IVIHuffDesc::huffDescCompare(const IVIHuffDesc *desc2) const {
+ return _numRows != desc2->_numRows || memcmp(_xBits, desc2->_xBits, _numRows);
+}
+
+void IVIHuffDesc::huffDescCopy(const IVIHuffDesc *src) {
+ _numRows = src->_numRows;
+ memcpy(_xBits, src->_xBits, src->_numRows);
+}
+
+/*------------------------------------------------------------------------*/
+
+IVIHuffTab::IVIHuffTab() : _tab(nullptr) {
+}
+
+int IVIHuffTab::decodeHuffDesc(IVI45DecContext *ctx, int descCoded, int whichTab) {
+ int i, result;
+ IVIHuffDesc newHuff;
+
+ if (!descCoded) {
+ // select default table
+ _tab = (whichTab) ? &ctx->_iviBlkVlcTabs[7]
+ : &ctx->_iviMbVlcTabs[7];
+ return 0;
+ }
+
+ _tabSel = ctx->_gb->getBits(3);
+ if (_tabSel == 7) {
+ // custom huffman table (explicitly encoded)
+ newHuff._numRows = ctx->_gb->getBits(4);
+ if (!newHuff._numRows) {
+ warning("Empty custom Huffman table!");
+ return -1;
+ }
+
+ for (i = 0; i < newHuff._numRows; i++)
+ newHuff._xBits[i] = ctx->_gb->getBits(4);
+
+ // Have we got the same custom table? Rebuild if not.
+ if (newHuff.huffDescCompare(&_custDesc) || !_custTab._table) {
+ _custDesc.huffDescCopy(&newHuff);
+
+ if (_custTab._table)
+ _custTab.freeVlc();
+ result = _custDesc.createHuffFromDesc(&_custTab, false);
+ if (result) {
+ // reset faulty description
+ _custDesc._numRows = 0;
+ warning("Error while initializing custom vlc table!");
+ return result;
+ }
+ }
+ _tab = &_custTab;
+ } else {
+ // select one of predefined tables
+ _tab = (whichTab) ? &ctx->_iviBlkVlcTabs[_tabSel]
+ : &ctx->_iviMbVlcTabs[_tabSel];
+ }
+
+ return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+IVIMbInfo::IVIMbInfo() : _xPos(0), _yPos(0), _bufOffs(0), _type(0), _cbp(0),
+ _qDelta(0), _mvX(0), _mvY(0), _bMvX(0), _bMvY(0) {
+}
+
+/*------------------------------------------------------------------------*/
+
+IVITile::IVITile() : _xPos(0), _yPos(0), _width(0), _height(0), _mbSize(0),
+ _isEmpty(false), _dataSize(0), _numMBs(0), _mbs(nullptr), _refMbs(nullptr) {
+}
+
+/*------------------------------------------------------------------------*/
+
+IVIBandDesc::IVIBandDesc() : _plane(0), _bandNum(0), _width(0), _height(0),
+ _aHeight(0), _dataPtr(nullptr), _dataSize(0), _buf(nullptr),
+ _refBuf(nullptr), _bRefBuf(nullptr), _pitch(0), _isEmpty(false),
+ _mbSize(0), _blkSize(0), _isHalfpel(false), _inheritMv(false), _bufSize(0),
+ _inheritQDelta(false), _qdeltaPresent(false), _quantMat(0), _globQuant(0),
+ _scan(nullptr), _scanSize(0), _numCorr(0), _rvmapSel(0), _rvMap(nullptr),
+ _numTiles(0), _tiles(nullptr), _invTransform(nullptr), _transformSize(0),
+ _dcTransform(nullptr), _is2dTrans(0), _checksum(0), _checksumPresent(false),
+ _intraBase(nullptr), _interBase(nullptr), _intraScale(nullptr),
+ _interScale(nullptr) {
+ Common::fill(&_bufs[0], &_bufs[4], (int16 *)nullptr);
+ Common::fill(&_corr[0], &_corr[61 * 2], 0);
+}
+
+int IVIBandDesc::initTiles(IVITile *refTile, int p, int b, int tHeight, int tWidth) {
+ int x, y;
+ IVITile *tile = _tiles;
+
+ for (y = 0; y < _height; y += tHeight) {
+ for (x = 0; x < _width; x += tWidth) {
+ tile->_xPos = x;
+ tile->_yPos = y;
+ tile->_mbSize = _mbSize;
+ tile->_width = MIN(_width - x, tWidth);
+ tile->_height = MIN(_height - y, tHeight);
+ tile->_dataSize = 0;
+ tile->_isEmpty = false;
+
+ // calculate number of macroblocks
+ tile->_numMBs = IVI_MBs_PER_TILE(tile->_width, tile->_height,
+ _mbSize);
+
+ avFreeP(&tile->_mbs);
+ tile->_mbs = (IVIMbInfo *)avMallocZArray(tile->_numMBs, sizeof(IVIMbInfo));
+ if (!tile->_mbs)
+ return -2;
+
+ tile->_refMbs = 0;
+ if (p || b) {
+ if (tile->_numMBs != refTile->_numMBs) {
+ warning("refTile mismatch");
+ return -1;
+ }
+ tile->_refMbs = refTile->_mbs;
+ refTile++;
+ }
+ tile++;
+ }
+ }
+
+ return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+IVIPicConfig::IVIPicConfig() : _picWidth(0), _picHeight(0), _chromaWidth(0),
+ _chromaHeight(0), _tileWidth(0), _tileHeight(0), _lumaBands(0), _chromaBands(0) {
+}
+
+bool IVIPicConfig::ivi_pic_config_cmp(const IVIPicConfig &cfg2) {
+ return _picWidth != cfg2._picWidth || _picHeight != cfg2._picHeight ||
+ _chromaWidth != cfg2._chromaWidth || _chromaHeight != cfg2._chromaHeight ||
+ _tileWidth != cfg2._tileWidth || _tileHeight != cfg2._tileHeight ||
+ _lumaBands != cfg2._lumaBands || _chromaBands != cfg2._chromaBands;
+}
+
+/*------------------------------------------------------------------------*/
+
+IVIPlaneDesc::IVIPlaneDesc() : _width(0), _height(0), _numBands(0), _bands(nullptr) {
+}
+
+int IVIPlaneDesc::initPlanes(IVIPlaneDesc *planes, const IVIPicConfig *cfg, bool isIndeo4) {
+ int p, b;
+ uint32 b_width, b_height, align_fac, width_aligned, height_aligned, bufSize;
+ IVIBandDesc *band;
+
+ freeBuffers(planes);
+
+ if (checkImageSize(cfg->_picWidth, cfg->_picHeight, 0) < 0 ||
+ cfg->_lumaBands < 1 || cfg->_chromaBands < 1)
+ return -1;
+
+ // fill in the descriptor of the luminance _plane
+ planes[0]._width = cfg->_picWidth;
+ planes[0]._height = cfg->_picHeight;
+ planes[0]._numBands = cfg->_lumaBands;
+
+ // fill in the descriptors of the chrominance planes
+ planes[1]._width = planes[2]._width = (cfg->_picWidth + 3) >> 2;
+ planes[1]._height = planes[2]._height = (cfg->_picHeight + 3) >> 2;
+ planes[1]._numBands = planes[2]._numBands = cfg->_chromaBands;
+
+ for (p = 0; p < 3; p++) {
+ planes[p]._bands = (IVIBandDesc *)avMallocZArray(planes[p]._numBands, sizeof(IVIBandDesc));
+ if (!planes[p]._bands)
+ return -2;
+
+ // select band dimensions: if there is only one band then it
+ // has the full size, if there are several bands each of them
+ // has only half size
+ b_width = planes[p]._numBands == 1 ? planes[p]._width
+ : (planes[p]._width + 1) >> 1;
+ b_height = planes[p]._numBands == 1 ? planes[p]._height
+ : (planes[p]._height + 1) >> 1;
+
+ // luma band buffers will be aligned on 16x16 (max macroblock size)
+ // chroma band buffers will be aligned on 8x8 (max macroblock size)
+ align_fac = p ? 8 : 16;
+ width_aligned = FFALIGN(b_width, align_fac);
+ height_aligned = FFALIGN(b_height, align_fac);
+ bufSize = width_aligned * height_aligned * sizeof(int16);
+
+ for (b = 0; b < planes[p]._numBands; b++) {
+ band = &planes[p]._bands[b]; // select appropriate _plane/band
+ band->_plane = p;
+ band->_bandNum = b;
+ band->_width = b_width;
+ band->_height = b_height;
+ band->_pitch = width_aligned;
+ band->_aHeight = height_aligned;
+ band->_bufs[0] = (int16 *)avMallocZ(bufSize);
+ band->_bufs[1] = (int16 *)avMallocZ(bufSize);
+ band->_bufSize = bufSize / 2;
+ if (!band->_bufs[0] || !band->_bufs[1])
+ return -2;
+
+ // allocate the 3rd band buffer for scalability mode
+ if (cfg->_lumaBands > 1) {
+ band->_bufs[2] = (int16 *)avMallocZ(bufSize);
+ if (!band->_bufs[2])
+ return -2;
+ }
+ if (isIndeo4) {
+ band->_bufs[3] = (int16 *)avMallocZ(bufSize);
+ if (!band->_bufs[3])
+ return -2;
+ }
+ // reset custom vlc
+ planes[p]._bands[0]._blkVlc._custDesc._numRows = 0;
+ }
+ }
+
+ return 0;
+}
+
+int IVIPlaneDesc::initTiles(IVIPlaneDesc *planes, int tileWidth, int tileHeight) {
+ int p, b, xTiles, yTiles, tWidth, tHeight, ret;
+ IVIBandDesc *band;
+
+ for (p = 0; p < 3; p++) {
+ tWidth = !p ? tileWidth : (tileWidth + 3) >> 2;
+ tHeight = !p ? tileHeight : (tileHeight + 3) >> 2;
+
+ if (!p && planes[0]._numBands == 4) {
+ tWidth >>= 1;
+ tHeight >>= 1;
+ }
+ if (tWidth <= 0 || tHeight <= 0)
+ return -3;
+
+ for (b = 0; b < planes[p]._numBands; b++) {
+ band = &planes[p]._bands[b];
+ xTiles = IVI_NUM_TILES(band->_width, tWidth);
+ yTiles = IVI_NUM_TILES(band->_height, tHeight);
+ band->_numTiles = xTiles * yTiles;
+
+ avFreeP(&band->_tiles);
+ band->_tiles = (IVITile *)avMallocZArray(band->_numTiles, sizeof(IVITile));
+ if (!band->_tiles)
+ return -2;
+
+ // use the first luma band as reference for motion vectors
+ // and quant
+ ret = band->initTiles(planes[0]._bands[0]._tiles,
+ p, b, tHeight, tWidth);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+void IVIPlaneDesc::freeBuffers(IVIPlaneDesc *planes) {
+ int p, b, t;
+
+ for (p = 0; p < 3; p++) {
+ if (planes[p]._bands)
+ for (b = 0; b < planes[p]._numBands; b++) {
+ avFreeP(&planes[p]._bands[b]._bufs[0]);
+ avFreeP(&planes[p]._bands[b]._bufs[1]);
+ avFreeP(&planes[p]._bands[b]._bufs[2]);
+ avFreeP(&planes[p]._bands[b]._bufs[3]);
+
+ if (planes[p]._bands[b]._blkVlc._custTab._table)
+ planes[p]._bands[b]._blkVlc._custTab.freeVlc();
+ for (t = 0; t < planes[p]._bands[b]._numTiles; t++)
+ avFreeP(&planes[p]._bands[b]._tiles[t]._mbs);
+ avFreeP(&planes[p]._bands[b]._tiles);
+ }
+ avFreeP(&planes[p]._bands);
+ planes[p]._numBands = 0;
+ }
+}
+
+int IVIPlaneDesc::checkImageSize(unsigned int w, unsigned int h, int log_offset) {
+ if (((w + 128) * (uint64)(h + 128)) < (MAX_INTEGER / 8))
+ return 0;
+
+ error("Picture size %ux%u is invalid", w, h);
+}
+
+/*------------------------------------------------------------------------*/
+
+AVFrame::AVFrame() {
+ Common::fill(&_data[0], &_data[AV_NUM_DATA_POINTERS], (uint8 *)nullptr);
+ Common::fill(&_linesize[0], &_linesize[AV_NUM_DATA_POINTERS], 0);
+}
+
+int AVFrame::setDimensions(uint16 width, uint16 height) {
+ _width = width;
+ _height = height;
+ _linesize[0] = _linesize[1] = _linesize[2] = width;
+
+ return 0;
+}
+
+int AVFrame::getBuffer(int flags) {
+ freeFrame();
+
+ // Luminance channel
+ _data[0] = (uint8 *)avMallocZ(_width * _height);
+
+ // UV Chroma Channels
+ _data[1] = (uint8 *)malloc(_width * _height);
+ _data[2] = (uint8 *)malloc(_width * _height);
+ Common::fill(_data[1], _data[1] + _width * _height, 0x80);
+ Common::fill(_data[2], _data[2] + _width * _height, 0x80);
+
+ return 0;
+}
+
+void AVFrame::freeFrame() {
+ avFreeP(&_data[0]);
+ avFreeP(&_data[1]);
+ avFreeP(&_data[2]);
+}
+
+/*------------------------------------------------------------------------*/
+
+IVI45DecContext::IVI45DecContext() : _gb(nullptr), _frameNum(0), _frameType(0),
+ _prevFrameType(0), _dataSize(0), _isScalable(0), _frameData(0),
+ _interScal(0), _frameSize(0), _picHdrSize(0), _frameFlags(0),
+ _checksum(0), _bufSwitch(0), _dstBuf(0), _refBuf(0), _ref2Buf(0),
+ _bRefBuf(0), _rvmapSel(0), _inImf(false), _inQ(false), _picGlobQuant(0),
+ _unknown1(0), _gopHdrSize(0), _gopFlags(0), _lockWord(0), _hasBFrames(false),
+ _hasTransp(false), _usesTiling(false), _usesHaar(false), _usesFullpel(false),
+ _gopInvalid(false), _isIndeo4(false), _pFrame(nullptr), _gotPFrame(false) {
+ Common::fill(&_bufInvalid[0], &_bufInvalid[4], 0);
+ Common::copy(&_ff_ivi_rvmap_tabs[0], &_ff_ivi_rvmap_tabs[9], &_rvmapTabs[0]);
+
+ for (int idx = 0; idx < (8192 * 16); ++idx)
+ _tableData[idx][0] = _tableData[idx][1] = 0;
+
+ for (int i = 0; i < 8; i++) {
+ _iviMbVlcTabs[i]._table = _tableData + i * 2 * 8192;
+ _iviMbVlcTabs[i]._tableAllocated = 8192;
+ ivi_mb_huff_desc[i].createHuffFromDesc(&_iviMbVlcTabs[i], true);
+ _iviBlkVlcTabs[i]._table = _tableData + (i * 2 + 1) * 8192;
+ _iviBlkVlcTabs[i]._tableAllocated = 8192;
+ ivi_blk_huff_desc[i].createHuffFromDesc(&_iviBlkVlcTabs[i], true);
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+IndeoDecoderBase::IndeoDecoderBase(uint16 width, uint16 height) : Codec() {
+ _pixelFormat = g_system->getScreenFormat();
+ assert(_pixelFormat.bytesPerPixel > 1);
+ _surface = new Graphics::ManagedSurface();
+ _surface->create(width, height, _pixelFormat);
+ _surface->fillRect(Common::Rect(0, 0, width, height), 0);
+ _ctx._bRefBuf = 3; // buffer 2 is used for scalability mode
+}
+
+IndeoDecoderBase::~IndeoDecoderBase() {
+ delete _surface;
+ IVIPlaneDesc::freeBuffers(_ctx._planes);
+ if (_ctx._mbVlc._custTab._table)
+ _ctx._mbVlc._custTab.freeVlc();
+
+ delete _ctx._pFrame;
+}
+
+int IndeoDecoderBase::decodeIndeoFrame() {
+ int result, p, b;
+ AVFrame frameData;
+ AVFrame *frame = &frameData;
+
+ // Decode the header
+ if (decodePictureHeader() < 0)
+ return -1;
+
+ if (_ctx._gopInvalid)
+ return -1;
+
+ if (_ctx._frameType == IVI4_FRAMETYPE_NULL_LAST) {
+ // Returning the previous frame, so exit wth success
+ return 0;
+ }
+
+ if (_ctx._gopFlags & IVI5_IS_PROTECTED) {
+ warning("Password-protected clip");
+ return -1;
+ }
+
+ if (!_ctx._planes[0]._bands) {
+ warning("Color planes not initialized yet");
+ return -1;
+ }
+
+ switchBuffers();
+
+ //{ START_TIMER;
+
+ if (isNonNullFrame()) {
+ _ctx._bufInvalid[_ctx._dstBuf] = 1;
+ for (p = 0; p < 3; p++) {
+ for (b = 0; b < _ctx._planes[p]._numBands; b++) {
+ result = decode_band(&_ctx._planes[p]._bands[b]);
+ if (result < 0) {
+ warning("Error while decoding band: %d, _plane: %d", b, p);
+ return result;
+ }
+ }
+ }
+ _ctx._bufInvalid[_ctx._dstBuf] = 0;
+ } else {
+ if (_ctx._isScalable)
+ return -1;
+
+ for (p = 0; p < 3; p++) {
+ if (!_ctx._planes[p]._bands[0]._buf)
+ return -1;
+ }
+ }
+ if (_ctx._bufInvalid[_ctx._dstBuf])
+ return -1;
+
+ //STOP_TIMER("decode_planes"); }
+
+ if (!isNonNullFrame())
+ return 0;
+
+ assert(_ctx._planes[0]._width <= _surface->w && _ctx._planes[0]._height <= _surface->h);
+ result = frame->setDimensions(_ctx._planes[0]._width, _ctx._planes[0]._height);
+ if (result < 0)
+ return result;
+
+ if ((result = frame->getBuffer(0)) < 0)
+ return result;
+
+ if (_ctx._isScalable) {
+ if (_ctx._isIndeo4)
+ recomposeHaar(&_ctx._planes[0], frame->_data[0], frame->_linesize[0]);
+ else
+ recompose53(&_ctx._planes[0], frame->_data[0], frame->_linesize[0]);
+ } else {
+ outputPlane(&_ctx._planes[0], frame->_data[0], frame->_linesize[0]);
+ }
+
+ outputPlane(&_ctx._planes[2], frame->_data[1], frame->_linesize[1]);
+ outputPlane(&_ctx._planes[1], frame->_data[2], frame->_linesize[2]);
+
+ // If the bidirectional mode is enabled, next I and the following P
+ // frame will be sent together. Unfortunately the approach below seems
+ // to be the only way to handle the B-frames mode.
+ // That's exactly the same Intel decoders do.
+ if (_ctx._isIndeo4 && _ctx._frameType == IVI4_FRAMETYPE_INTRA) {
+ int left;
+
+ // skip version string
+ while (_ctx._gb->getBits(8)) {
+ if (_ctx._gb->getBitsLeft() < 8)
+ return -1;
+ }
+ left = _ctx._gb->pos() & 0x18;
+ _ctx._gb->skip(64 - left);
+ if (_ctx._gb->getBitsLeft() > 18 &&
+ _ctx._gb->peekBits(21) == 0xBFFF8) { // syncheader + inter _type
+ error("Indeo decoder: Mode not currently implemented in ScummVM");
+ }
+ }
+
+ // Merge the planes into the final surface
+ Graphics::Surface s = _surface->getSubArea(Common::Rect(0, 0, _surface->w, _surface->h));
+ YUVToRGBMan.convert410(&s, Graphics::YUVToRGBManager::kScaleITU,
+ frame->_data[0], frame->_data[1], frame->_data[2], frame->_width, frame->_height,
+ frame->_width, frame->_width);
+
+ // Free the now un-needed frame data
+ frame->freeFrame();
+
+ return 0;
+}
+
+int IndeoDecoderBase::decode_band(IVIBandDesc *band) {
+ int result, i, t, idx1, idx2, pos;
+ IVITile *tile;
+
+ band->_buf = band->_bufs[_ctx._dstBuf];
+ if (!band->_buf) {
+ warning("Band buffer points to no data!");
+ return -1;
+ }
+ if (_ctx._isIndeo4 && _ctx._frameType == IVI4_FRAMETYPE_BIDIR) {
+ band->_refBuf = band->_bufs[_ctx._bRefBuf];
+ band->_bRefBuf = band->_bufs[_ctx._refBuf];
+ } else {
+ band->_refBuf = band->_bufs[_ctx._refBuf];
+ band->_bRefBuf = 0;
+ }
+ band->_dataPtr = _ctx._frameData + (_ctx._gb->pos() >> 3);
+
+ result = decodeBandHeader(band);
+ if (result) {
+ warning("Error while decoding band header: %d",
+ result);
+ return result;
+ }
+
+ if (band->_isEmpty) {
+ warning("Empty band encountered!");
+ return -1;
+ }
+
+ band->_rvMap = &_ctx._rvmapTabs[band->_rvmapSel];
+
+ // apply corrections to the selected rvmap table if present
+ for (i = 0; i < band->_numCorr; i++) {
+ idx1 = band->_corr[i * 2];
+ idx2 = band->_corr[i * 2 + 1];
+ SWAP(band->_rvMap->_runtab[idx1], band->_rvMap->_runtab[idx2]);
+ SWAP(band->_rvMap->_valtab[idx1], band->_rvMap->_valtab[idx2]);
+ if (idx1 == band->_rvMap->_eobSym || idx2 == band->_rvMap->_eobSym)
+ band->_rvMap->_eobSym ^= idx1 ^ idx2;
+ if (idx1 == band->_rvMap->_escSym || idx2 == band->_rvMap->_escSym)
+ band->_rvMap->_escSym ^= idx1 ^ idx2;
+ }
+
+ pos = _ctx._gb->pos();
+
+ for (t = 0; t < band->_numTiles; t++) {
+ tile = &band->_tiles[t];
+
+ if (tile->_mbSize != band->_mbSize) {
+ warning("MB sizes mismatch: %d vs. %d",
+ band->_mbSize, tile->_mbSize);
+ return -1;
+ }
+ tile->_isEmpty = _ctx._gb->getBit();
+ if (tile->_isEmpty) {
+ result = processEmptyTile(band, tile,
+ (_ctx._planes[0]._bands[0]._mbSize >> 3) - (band->_mbSize >> 3));
+ if (result < 0)
+ break;
+ warning("Empty tile encountered!");
+ } else {
+ tile->_dataSize = decodeTileDataSize(_ctx._gb);
+ if (!tile->_dataSize) {
+ warning("Tile data size is zero!");
+ result = -1;
+ break;
+ }
+
+ result = decodeMbInfo(band, tile);
+ if (result < 0)
+ break;
+
+ result = decodeBlocks(_ctx._gb, band, tile);
+ if (result < 0) {
+ warning("Corrupted tile data encountered!");
+ break;
+ }
+
+ if ((((int)_ctx._gb->pos() - pos) >> 3) != tile->_dataSize) {
+ warning("Tile _dataSize mismatch!");
+ result = -1;
+ break;
+ }
+
+ pos += tile->_dataSize << 3; // skip to next tile
+ }
+ }
+
+ // restore the selected rvmap table by applying its corrections in
+ // reverse order
+ for (i = band->_numCorr - 1; i >= 0; i--) {
+ idx1 = band->_corr[i * 2];
+ idx2 = band->_corr[i * 2 + 1];
+ SWAP(band->_rvMap->_runtab[idx1], band->_rvMap->_runtab[idx2]);
+ SWAP(band->_rvMap->_valtab[idx1], band->_rvMap->_valtab[idx2]);
+ if (idx1 == band->_rvMap->_eobSym || idx2 == band->_rvMap->_eobSym)
+ band->_rvMap->_eobSym ^= idx1 ^ idx2;
+ if (idx1 == band->_rvMap->_escSym || idx2 == band->_rvMap->_escSym)
+ band->_rvMap->_escSym ^= idx1 ^ idx2;
+ }
+
+ _ctx._gb->align();
+
+ return result;
+}
+
+void IndeoDecoderBase::recomposeHaar(const IVIPlaneDesc *_plane,
+ uint8 *dst, const int dstPitch) {
+ int x, y, indx, b0, b1, b2, b3, p0, p1, p2, p3;
+ const short *b0Ptr, *b1Ptr, *b2Ptr, *b3Ptr;
+ int32 pitch;
+
+ // all bands should have the same _pitch
+ pitch = _plane->_bands[0]._pitch;
+
+ // get pointers to the wavelet bands
+ b0Ptr = _plane->_bands[0]._buf;
+ b1Ptr = _plane->_bands[1]._buf;
+ b2Ptr = _plane->_bands[2]._buf;
+ b3Ptr = _plane->_bands[3]._buf;
+
+ for (y = 0; y < _plane->_height; y += 2) {
+ for (x = 0, indx = 0; x < _plane->_width; x += 2, indx++) {
+ // load coefficients
+ b0 = b0Ptr[indx]; //should be: b0 = (_numBands > 0) ? b0Ptr[indx] : 0;
+ b1 = b1Ptr[indx]; //should be: b1 = (_numBands > 1) ? b1Ptr[indx] : 0;
+ b2 = b2Ptr[indx]; //should be: b2 = (_numBands > 2) ? b2Ptr[indx] : 0;
+ b3 = b3Ptr[indx]; //should be: b3 = (_numBands > 3) ? b3Ptr[indx] : 0;
+
+ // haar wavelet recomposition
+ p0 = (b0 + b1 + b2 + b3 + 2) >> 2;
+ p1 = (b0 + b1 - b2 - b3 + 2) >> 2;
+ p2 = (b0 - b1 + b2 - b3 + 2) >> 2;
+ p3 = (b0 - b1 - b2 + b3 + 2) >> 2;
+
+ // bias, convert and output four pixels
+ dst[x] = avClipUint8(p0 + 128);
+ dst[x + 1] = avClipUint8(p1 + 128);
+ dst[dstPitch + x] = avClipUint8(p2 + 128);
+ dst[dstPitch + x + 1] = avClipUint8(p3 + 128);
+ }// for x
+
+ dst += dstPitch << 1;
+
+ b0Ptr += pitch;
+ b1Ptr += pitch;
+ b2Ptr += pitch;
+ b3Ptr += pitch;
+ }// for y
+}
+
+void IndeoDecoderBase::recompose53(const IVIPlaneDesc *_plane,
+ uint8 *dst, const int dstPitch) {
+ int x, y, indx;
+ int32 p0, p1, p2, p3, tmp0, tmp1, tmp2;
+ int32 b0_1, b0_2, b1_1, b1_2, b1_3, b2_1, b2_2, b2_3, b2_4, b2_5, b2_6;
+ int32 b3_1, b3_2, b3_3, b3_4, b3_5, b3_6, b3_7, b3_8, b3_9;
+ int32 _pitch, back_pitch;
+ const short *b0Ptr, *b1Ptr, *b2Ptr, *b3Ptr;
+ const int numBands = 4;
+
+ // all bands should have the same _pitch
+ _pitch = _plane->_bands[0]._pitch;
+
+ // pixels at the position "y-1" will be set to pixels at the "y" for the 1st iteration
+ back_pitch = 0;
+
+ // get pointers to the wavelet bands
+ b0Ptr = _plane->_bands[0]._buf;
+ b1Ptr = _plane->_bands[1]._buf;
+ b2Ptr = _plane->_bands[2]._buf;
+ b3Ptr = _plane->_bands[3]._buf;
+
+ for (y = 0; y < _plane->_height; y += 2) {
+
+ if (y + 2 >= _plane->_height)
+ _pitch = 0;
+ // load storage variables with values
+ if (numBands > 0) {
+ b0_1 = b0Ptr[0];
+ b0_2 = b0Ptr[_pitch];
+ }
+
+ if (numBands > 1) {
+ b1_1 = b1Ptr[back_pitch];
+ b1_2 = b1Ptr[0];
+ b1_3 = b1_1 - b1_2 * 6 + b1Ptr[_pitch];
+ }
+
+ if (numBands > 2) {
+ b2_2 = b2Ptr[0]; // b2[x, y ]
+ b2_3 = b2_2; // b2[x+1,y ] = b2[x,y]
+ b2_5 = b2Ptr[_pitch]; // b2[x ,y+1]
+ b2_6 = b2_5; // b2[x+1,y+1] = b2[x,y+1]
+ }
+
+ if (numBands > 3) {
+ b3_2 = b3Ptr[back_pitch]; // b3[x ,y-1]
+ b3_3 = b3_2; // b3[x+1,y-1] = b3[x ,y-1]
+ b3_5 = b3Ptr[0]; // b3[x ,y ]
+ b3_6 = b3_5; // b3[x+1,y ] = b3[x ,y ]
+ b3_8 = b3_2 - b3_5 * 6 + b3Ptr[_pitch];
+ b3_9 = b3_8;
+ }
+
+ for (x = 0, indx = 0; x < _plane->_width; x += 2, indx++) {
+ if (x + 2 >= _plane->_width) {
+ b0Ptr--;
+ b1Ptr--;
+ b2Ptr--;
+ b3Ptr--;
+ }
+
+ // some values calculated in the previous iterations can
+ // be reused in the next ones, so do appropriate copying
+ b2_1 = b2_2; // b2[x-1,y ] = b2[x, y ]
+ b2_2 = b2_3; // b2[x ,y ] = b2[x+1,y ]
+ b2_4 = b2_5; // b2[x-1,y+1] = b2[x ,y+1]
+ b2_5 = b2_6; // b2[x ,y+1] = b2[x+1,y+1]
+ b3_1 = b3_2; // b3[x-1,y-1] = b3[x ,y-1]
+ b3_2 = b3_3; // b3[x ,y-1] = b3[x+1,y-1]
+ b3_4 = b3_5; // b3[x-1,y ] = b3[x ,y ]
+ b3_5 = b3_6; // b3[x ,y ] = b3[x+1,y ]
+ b3_7 = b3_8; // vert_HPF(x-1)
+ b3_8 = b3_9; // vert_HPF(x )
+
+ p0 = p1 = p2 = p3 = 0;
+
+ // process the LL-band by applying LPF both vertically and horizontally
+ if (numBands > 0) {
+ tmp0 = b0_1;
+ tmp2 = b0_2;
+ b0_1 = b0Ptr[indx + 1];
+ b0_2 = b0Ptr[_pitch + indx + 1];
+ tmp1 = tmp0 + b0_1;
+
+ p0 = tmp0 << 4;
+ p1 = tmp1 << 3;
+ p2 = (tmp0 + tmp2) << 3;
+ p3 = (tmp1 + tmp2 + b0_2) << 2;
+ }
+
+ // process the HL-band by applying HPF vertically and LPF horizontally
+ if (numBands > 1) {
+ tmp0 = b1_2;
+ tmp1 = b1_1;
+ b1_2 = b1Ptr[indx + 1];
+ b1_1 = b1Ptr[back_pitch + indx + 1];
+
+ tmp2 = tmp1 - tmp0 * 6 + b1_3;
+ b1_3 = b1_1 - b1_2 * 6 + b1Ptr[_pitch + indx + 1];
+
+ p0 += (tmp0 + tmp1) << 3;
+ p1 += (tmp0 + tmp1 + b1_1 + b1_2) << 2;
+ p2 += tmp2 << 2;
+ p3 += (tmp2 + b1_3) << 1;
+ }
+
+ // process the LH-band by applying LPF vertically and HPF horizontally
+ if (numBands > 2) {
+ b2_3 = b2Ptr[indx + 1];
+ b2_6 = b2Ptr[_pitch + indx + 1];
+
+ tmp0 = b2_1 + b2_2;
+ tmp1 = b2_1 - b2_2 * 6 + b2_3;
+
+ p0 += tmp0 << 3;
+ p1 += tmp1 << 2;
+ p2 += (tmp0 + b2_4 + b2_5) << 2;
+ p3 += (tmp1 + b2_4 - b2_5 * 6 + b2_6) << 1;
+ }
+
+ // process the HH-band by applying HPF both vertically and horizontally
+ if (numBands > 3) {
+ b3_6 = b3Ptr[indx + 1]; // b3[x+1,y ]
+ b3_3 = b3Ptr[back_pitch + indx + 1]; // b3[x+1,y-1]
+
+ tmp0 = b3_1 + b3_4;
+ tmp1 = b3_2 + b3_5;
+ tmp2 = b3_3 + b3_6;
+
+ b3_9 = b3_3 - b3_6 * 6 + b3Ptr[_pitch + indx + 1];
+
+ p0 += (tmp0 + tmp1) << 2;
+ p1 += (tmp0 - tmp1 * 6 + tmp2) << 1;
+ p2 += (b3_7 + b3_8) << 1;
+ p3 += b3_7 - b3_8 * 6 + b3_9;
+ }
+
+ // output four pixels
+ dst[x] = avClipUint8((p0 >> 6) + 128);
+ dst[x + 1] = avClipUint8((p1 >> 6) + 128);
+ dst[dstPitch + x] = avClipUint8((p2 >> 6) + 128);
+ dst[dstPitch + x + 1] = avClipUint8((p3 >> 6) + 128);
+ }// for x
+
+ dst += dstPitch << 1;
+
+ back_pitch = -_pitch;
+
+ b0Ptr += _pitch + 1;
+ b1Ptr += _pitch + 1;
+ b2Ptr += _pitch + 1;
+ b3Ptr += _pitch + 1;
+ }
+}
+
+void IndeoDecoderBase::outputPlane(IVIPlaneDesc *_plane, uint8 *dst, int dstPitch) {
+ int x, y;
+ const int16 *src = _plane->_bands[0]._buf;
+ uint32 pitch = _plane->_bands[0]._pitch;
+
+ if (!src)
+ return;
+
+ for (y = 0; y < _plane->_height; y++) {
+ for (x = 0; x < _plane->_width; x++)
+ dst[x] = avClipUint8(src[x] + 128);
+ src += pitch;
+ dst += dstPitch;
+ }
+}
+
+int IndeoDecoderBase::processEmptyTile(IVIBandDesc *band,
+ IVITile *tile, int32 mvScale) {
+ int x, y, needMc, mbn, blk, numBlocks, mvX, mvY, mcType;
+ int offs, mbOffset, rowOffset, ret;
+ IVIMbInfo *mb, *refMb;
+ const int16 *src;
+ int16 *dst;
+ IviMCFunc mcNoDeltaFunc;
+
+ if (tile->_numMBs != IVI_MBs_PER_TILE(tile->_width, tile->_height, band->_mbSize)) {
+ warning("Allocated tile size %d mismatches "
+ "parameters %d in processEmptyTile()",
+ tile->_numMBs, IVI_MBs_PER_TILE(tile->_width, tile->_height, band->_mbSize));
+ return -1;
+ }
+
+ offs = tile->_yPos * band->_pitch + tile->_xPos;
+ mb = tile->_mbs;
+ refMb = tile->_refMbs;
+ rowOffset = band->_mbSize * band->_pitch;
+ needMc = 0; // reset the mc tracking flag
+
+ for (y = tile->_yPos; y < (tile->_yPos + tile->_height); y += band->_mbSize) {
+ mbOffset = offs;
+
+ for (x = tile->_xPos; x < (tile->_xPos + tile->_width); x += band->_mbSize) {
+ mb->_xPos = x;
+ mb->_yPos = y;
+ mb->_bufOffs = mbOffset;
+
+ mb->_type = 1; // set the macroblocks _type = INTER
+ mb->_cbp = 0; // all blocks are empty
+
+ if (!band->_qdeltaPresent && !band->_plane && !band->_bandNum) {
+ mb->_qDelta = band->_globQuant;
+ mb->_mvX = 0;
+ mb->_mvY = 0;
+ }
+
+ if (band->_inheritQDelta && refMb)
+ mb->_qDelta = refMb->_qDelta;
+
+ if (band->_inheritMv && refMb) {
+ // motion vector inheritance
+ if (mvScale) {
+ mb->_mvX = scaleMV(refMb->_mvX, mvScale);
+ mb->_mvY = scaleMV(refMb->_mvY, mvScale);
+ } else {
+ mb->_mvX = refMb->_mvX;
+ mb->_mvY = refMb->_mvY;
+ }
+ needMc |= mb->_mvX || mb->_mvY; // tracking non-zero motion vectors
+ {
+ int dmv_x, dmv_y, cx, cy;
+
+ dmv_x = mb->_mvX >> band->_isHalfpel;
+ dmv_y = mb->_mvY >> band->_isHalfpel;
+ cx = mb->_mvX & band->_isHalfpel;
+ cy = mb->_mvY & band->_isHalfpel;
+
+ if (mb->_xPos + dmv_x < 0
+ || mb->_xPos + dmv_x + band->_mbSize + cx > band->_pitch
+ || mb->_yPos + dmv_y < 0
+ || mb->_yPos + dmv_y + band->_mbSize + cy > band->_aHeight) {
+ warning("MV out of bounds");
+ return -1;
+ }
+ }
+ }
+
+ mb++;
+ if (refMb)
+ refMb++;
+ mbOffset += band->_mbSize;
+ } // for x
+ offs += rowOffset;
+ } // for y
+
+ if (band->_inheritMv && needMc) { // apply motion compensation if there is at least one non-zero motion vector
+ numBlocks = (band->_mbSize != band->_blkSize) ? 4 : 1; // number of blocks per mb
+ mcNoDeltaFunc = (band->_blkSize == 8) ? IndeoDSP::ffIviMc8x8NoDelta
+ : IndeoDSP::ffIviMc4x4NoDelta;
+
+ for (mbn = 0, mb = tile->_mbs; mbn < tile->_numMBs; mb++, mbn++) {
+ mvX = mb->_mvX;
+ mvY = mb->_mvY;
+ if (!band->_isHalfpel) {
+ mcType = 0; // we have only fullpel vectors
+ } else {
+ mcType = ((mvY & 1) << 1) | (mvX & 1);
+ mvX >>= 1;
+ mvY >>= 1; // convert halfpel vectors into fullpel ones
+ }
+
+ for (blk = 0; blk < numBlocks; blk++) {
+ // adjust block position in the buffer according with its number
+ offs = mb->_bufOffs + band->_blkSize * ((blk & 1) + !!(blk & 2) * band->_pitch);
+ ret = iviMc(band, mcNoDeltaFunc, nullptr, offs,
+ mvX, mvY, 0, 0, mcType, -1);
+ if (ret < 0)
+ return ret;
+ }
+ }
+ } else {
+ // copy data from the reference tile into the current one
+ src = band->_refBuf + tile->_yPos * band->_pitch + tile->_xPos;
+ dst = band->_buf + tile->_yPos * band->_pitch + tile->_xPos;
+ for (y = 0; y < tile->_height; y++) {
+ memcpy(dst, src, tile->_width*sizeof(band->_buf[0]));
+ src += band->_pitch;
+ dst += band->_pitch;
+ }
+ }
+
+ return 0;
+}
+
+int IndeoDecoderBase::decodeTileDataSize(GetBits *gb) {
+ int len = 0;
+
+ if (gb->getBit()) {
+ len = gb->getBits(8);
+ if (len == 255)
+ len = gb->getBits(24);
+ }
+
+ // align the bitstream reader on the byte boundary
+ gb->align();
+
+ return len;
+}
+
+int IndeoDecoderBase::decodeBlocks(GetBits *_gb, IVIBandDesc *band, IVITile *tile) {
+ int mbn, blk, numBlocks, blkSize, ret, isIntra;
+ int mcType = 0, mcType2 = -1;
+ int mvX = 0, mvY = 0, mvX2 = 0, mvY2 = 0;
+ int32 prevDc;
+ uint32 cbp, quant, bufOffs;
+ IVIMbInfo *mb;
+ IviMCFunc mcWithDeltaFunc, mcNoDeltaFunc;
+ IviMCAvgFunc mcAvgWithDeltaFunc, mcAvgNoDeltaFunc;
+ const uint8 *scaleTab;
+
+ // init intra prediction for the DC coefficient
+ prevDc = 0;
+ blkSize = band->_blkSize;
+ // number of blocks per mb
+ numBlocks = (band->_mbSize != blkSize) ? 4 : 1;
+ if (blkSize == 8) {
+ mcWithDeltaFunc = IndeoDSP::ffIviMc8x8Delta;
+ mcNoDeltaFunc = IndeoDSP::ffIviMc8x8NoDelta;
+ mcAvgWithDeltaFunc = IndeoDSP::ffIviMcAvg8x8Delta;
+ mcAvgNoDeltaFunc = IndeoDSP::ffIviMcAvg8x8NoDelta;
+ } else {
+ mcWithDeltaFunc = IndeoDSP::ffIviMc4x4Delta;
+ mcNoDeltaFunc = IndeoDSP::ffIviMc4x4NoDelta;
+ mcAvgWithDeltaFunc = IndeoDSP::ffIviMcAvg4x4Delta;
+ mcAvgNoDeltaFunc = IndeoDSP::ffIviMcAvg4x4NoDelta;
+ }
+
+ for (mbn = 0, mb = tile->_mbs; mbn < tile->_numMBs; mb++, mbn++) {
+ isIntra = !mb->_type;
+ cbp = mb->_cbp;
+ bufOffs = mb->_bufOffs;
+
+ quant = band->_globQuant + mb->_qDelta;
+ if (_ctx._isIndeo4)
+ quant = avClipUintp2(quant, 5);
+ else
+ quant = av_clip((int)quant, 0, 23);
+
+ scaleTab = isIntra ? band->_intraScale : band->_interScale;
+ if (scaleTab)
+ quant = scaleTab[quant];
+
+ if (!isIntra) {
+ mvX = mb->_mvX;
+ mvY = mb->_mvY;
+ mvX2 = mb->_bMvX;
+ mvY2 = mb->_bMvY;
+ if (band->_isHalfpel) {
+ mcType = ((mvY & 1) << 1) | (mvX & 1);
+ mcType2 = ((mvY2 & 1) << 1) | (mvX2 & 1);
+ mvX >>= 1;
+ mvY >>= 1;
+ mvX2 >>= 1;
+ mvY2 >>= 1; // convert halfpel vectors into fullpel ones
+ }
+ if (mb->_type == 2)
+ mcType = -1;
+ if (mb->_type != 2 && mb->_type != 3)
+ mcType2 = -1;
+ if (mb->_type) {
+ int dmv_x, dmv_y, cx, cy;
+
+ dmv_x = mb->_mvX >> band->_isHalfpel;
+ dmv_y = mb->_mvY >> band->_isHalfpel;
+ cx = mb->_mvX & band->_isHalfpel;
+ cy = mb->_mvY & band->_isHalfpel;
+
+ if (mb->_xPos + dmv_x < 0 ||
+ mb->_xPos + dmv_x + band->_mbSize + cx > band->_pitch ||
+ mb->_yPos + dmv_y < 0 ||
+ mb->_yPos + dmv_y + band->_mbSize + cy > band->_aHeight) {
+ return -1;
+ }
+ }
+ if (mb->_type == 2 || mb->_type == 3) {
+ int dmv_x, dmv_y, cx, cy;
+
+ dmv_x = mb->_bMvX >> band->_isHalfpel;
+ dmv_y = mb->_bMvY >> band->_isHalfpel;
+ cx = mb->_bMvX & band->_isHalfpel;
+ cy = mb->_bMvY & band->_isHalfpel;
+
+ if (mb->_xPos + dmv_x < 0 ||
+ mb->_xPos + dmv_x + band->_mbSize + cx > band->_pitch ||
+ mb->_yPos + dmv_y < 0 ||
+ mb->_yPos + dmv_y + band->_mbSize + cy > band->_aHeight) {
+ return -1;
+ }
+ }
+ }
+
+ for (blk = 0; blk < numBlocks; blk++) {
+ // adjust block position in the buffer according to its number
+ if (blk & 1) {
+ bufOffs += blkSize;
+ } else if (blk == 2) {
+ bufOffs -= blkSize;
+ bufOffs += blkSize * band->_pitch;
+ }
+
+ if (cbp & 1) { // block coded ?
+ ret = ivi_decode_coded_blocks(_gb, band, mcWithDeltaFunc,
+ mcAvgWithDeltaFunc,
+ mvX, mvY, mvX2, mvY2,
+ &prevDc, isIntra,
+ mcType, mcType2, quant,
+ bufOffs);
+ if (ret < 0)
+ return ret;
+ } else {
+ // block not coded
+ // for intra blocks apply the dc slant transform
+ // for inter - perform the motion compensation without delta
+ if (isIntra) {
+ ret = ivi_dc_transform(band, &prevDc, bufOffs, blkSize);
+ if (ret < 0)
+ return ret;
+ } else {
+ ret = iviMc(band, mcNoDeltaFunc, mcAvgNoDeltaFunc,
+ bufOffs, mvX, mvY, mvX2, mvY2,
+ mcType, mcType2);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ cbp >>= 1;
+ }// for blk
+ }// for mbn
+
+ _gb->align();
+ return 0;
+}
+
+int IndeoDecoderBase::scaleMV(int mv, int mvScale) {
+ return (mv + (mv > 0) + (mvScale - 1)) >> mvScale;
+}
+
+int IndeoDecoderBase::iviMc(IVIBandDesc *band, IviMCFunc mc, IviMCAvgFunc mcAvg,
+ int offs, int mvX, int mvY, int mvX2, int mvY2,
+ int mcType, int mcType2) {
+ int refOffs = offs + mvY * band->_pitch + mvX;
+ int bufSize = band->_pitch * band->_aHeight;
+ int minSize = band->_pitch * (band->_blkSize - 1) + band->_blkSize;
+ int refSize = (mcType > 1) * band->_pitch + (mcType & 1);
+
+ if (mcType != -1) {
+ assert(offs >= 0 && refOffs >= 0 && band->_refBuf);
+ assert(bufSize - minSize >= offs);
+ assert(bufSize - minSize - refSize >= refOffs);
+ }
+
+ if (mcType2 == -1) {
+ mc(band->_buf + offs, band->_refBuf + refOffs, band->_pitch, mcType);
+ } else {
+ int ref_offs2 = offs + mvY2 * band->_pitch + mvX2;
+ int ref_size2 = (mcType2 > 1) * band->_pitch + (mcType2 & 1);
+ if (offs < 0 || ref_offs2 < 0 || !band->_bRefBuf)
+ return -1;
+ if (bufSize - minSize - ref_size2 < ref_offs2)
+ return -1;
+
+ if (mcType == -1)
+ mc(band->_buf + offs, band->_bRefBuf + ref_offs2,
+ band->_pitch, mcType2);
+ else
+ mcAvg(band->_buf + offs, band->_refBuf + refOffs,
+ band->_bRefBuf + ref_offs2, band->_pitch,
+ mcType, mcType2);
+ }
+
+ return 0;
+}
+
+int IndeoDecoderBase::ivi_decode_coded_blocks(GetBits *gb, IVIBandDesc *band,
+ IviMCFunc mc, IviMCAvgFunc mcAvg, int mvX, int mvY,
+ int mvX2, int mvY2, int *prevDc, int isIntra,
+ int mcType, int mcType2, uint32 quant, int offs) {
+ const uint16 *baseTab = isIntra ? band->_intraBase : band->_interBase;
+ RVMapDesc *rvmap = band->_rvMap;
+ uint8 colFlags[8];
+ int32 trvec[64];
+ uint32 sym = 0, q;
+ int lo, hi;
+ int pos, run, val;
+ int blkSize = band->_blkSize;
+ int numCoeffs = blkSize * blkSize;
+ int colMask = blkSize - 1;
+ int scanPos = -1;
+ int minSize = band->_pitch * (band->_transformSize - 1) +
+ band->_transformSize;
+ int bufSize = band->_pitch * band->_aHeight - offs;
+
+ if (minSize > bufSize)
+ return -1;
+
+ if (!band->_scan) {
+ warning("Scan pattern is not set.");
+ return -1;
+ }
+
+ // zero transform vector
+ memset(trvec, 0, numCoeffs * sizeof(trvec[0]));
+ // zero column flags
+ memset(colFlags, 0, sizeof(colFlags));
+ while (scanPos <= numCoeffs) {
+ sym = gb->getVLC2(band->_blkVlc._tab->_table,
+ IVI_VLC_BITS, 1);
+ if (sym == rvmap->_eobSym)
+ break; // End of block
+
+ // Escape - run/val explicitly coded using 3 vlc codes
+ if (sym == rvmap->_escSym) {
+ run = gb->getVLC2(band->_blkVlc._tab->_table, IVI_VLC_BITS, 1) + 1;
+ lo = gb->getVLC2(band->_blkVlc._tab->_table, IVI_VLC_BITS, 1);
+ hi = gb->getVLC2(band->_blkVlc._tab->_table, IVI_VLC_BITS, 1);
+ // merge them and convert into signed val
+ val = IVI_TOSIGNED((hi << 6) | lo);
+ } else {
+ if (sym >= 256U) {
+ warning("Invalid sym encountered");
+ return -1;
+ }
+ run = rvmap->_runtab[sym];
+ val = rvmap->_valtab[sym];
+ }
+
+ // de-zigzag and dequantize
+ scanPos += run;
+ if (scanPos >= numCoeffs || scanPos < 0)
+ break;
+ pos = band->_scan[scanPos];
+
+ if (!val)
+ warning("Val = 0 encountered!");
+
+ q = (baseTab[pos] * quant) >> 9;
+ if (q > 1)
+ val = val * q + FFSIGN(val) * (((q ^ 1) - 1) >> 1);
+ trvec[pos] = val;
+ // track columns containing non-zero coeffs
+ colFlags[pos & colMask] |= !!val;
+ }
+
+ if (scanPos < 0 || (scanPos >= numCoeffs && sym != rvmap->_eobSym))
+ return -1; // corrupt block data
+
+ // undoing DC coeff prediction for intra-blocks
+ if (isIntra && band->_is2dTrans) {
+ *prevDc += trvec[0];
+ trvec[0] = *prevDc;
+ colFlags[0] |= !!*prevDc;
+ }
+
+ if (band->_transformSize > band->_blkSize) {
+ warning("Too large transform");
+ return -1;
+ }
+
+ // apply inverse transform
+ band->_invTransform(trvec, band->_buf + offs,
+ band->_pitch, colFlags);
+
+ // apply motion compensation
+ if (!isIntra)
+ return iviMc(band, mc, mcAvg, offs, mvX, mvY, mvX2, mvY2,
+ mcType, mcType2);
+
+ return 0;
+}
+
+int IndeoDecoderBase::ivi_dc_transform(IVIBandDesc *band, int *prevDc,
+ int bufOffs, int blkSize) {
+ int bufSize = band->_pitch * band->_aHeight - bufOffs;
+ int minSize = (blkSize - 1) * band->_pitch + blkSize;
+
+ if (minSize > bufSize)
+ return -1;
+
+ band->_dcTransform(prevDc, band->_buf + bufOffs,
+ band->_pitch, blkSize);
+
+ return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+const uint8 IndeoDecoderBase::_ffIviVerticalScan8x8[64] = {
+ 0, 8, 16, 24, 32, 40, 48, 56,
+ 1, 9, 17, 25, 33, 41, 49, 57,
+ 2, 10, 18, 26, 34, 42, 50, 58,
+ 3, 11, 19, 27, 35, 43, 51, 59,
+ 4, 12, 20, 28, 36, 44, 52, 60,
+ 5, 13, 21, 29, 37, 45, 53, 61,
+ 6, 14, 22, 30, 38, 46, 54, 62,
+ 7, 15, 23, 31, 39, 47, 55, 63
+};
+
+const uint8 IndeoDecoderBase::_ffIviHorizontalScan8x8[64] = {
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63
+};
+
+const uint8 IndeoDecoderBase::_ffIviDirectScan4x4[16] = {
+ 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15
+};
+
+const RVMapDesc IVI45DecContext::_ff_ivi_rvmap_tabs[9] = {
+{ // MapTab0
+ 5, // _eobSym
+ 2, // _escSym
+ // run table
+ {1, 1, 0, 1, 1, 0, 1, 1, 2, 2, 1, 1, 1, 1, 3, 3,
+ 1, 1, 2, 2, 1, 1, 4, 4, 1, 1, 1, 1, 2, 2, 5, 5,
+ 1, 1, 3, 3, 1, 1, 6, 6, 1, 2, 1, 2, 7, 7, 1, 1,
+ 8, 8, 1, 1, 4, 2, 1, 4, 2, 1, 3, 3, 1, 1, 1, 9,
+ 9, 1, 2, 1, 2, 1, 5, 5, 1, 1, 10, 10, 1, 1, 3, 3,
+ 2, 2, 1, 1, 11, 11, 6, 4, 4, 1, 6, 1, 2, 1, 2, 12,
+ 8, 1, 12, 7, 8, 7, 1, 16, 1, 16, 1, 3, 3, 13, 1, 13,
+ 2, 2, 1, 15, 1, 5, 14, 15, 1, 5, 14, 1, 17, 8, 17, 8,
+ 1, 4, 4, 2, 2, 1, 25, 25, 24, 24, 1, 3, 1, 3, 1, 8,
+ 6, 7, 6, 1, 18, 8, 18, 1, 7, 23, 2, 2, 23, 1, 1, 21,
+ 22, 9, 9, 22, 19, 1, 21, 5, 19, 5, 1, 33, 20, 33, 20, 8,
+ 4, 4, 1, 32, 2, 2, 8, 3, 32, 26, 3, 1, 7, 7, 26, 6,
+ 1, 6, 1, 1, 16, 1, 10, 1, 10, 2, 16, 29, 28, 2, 29, 28,
+ 1, 27, 5, 8, 5, 27, 1, 8, 3, 7, 3, 31, 41, 31, 1, 41,
+ 6, 1, 6, 7, 4, 4, 1, 1, 2, 1, 2, 11, 34, 30, 11, 1,
+ 30, 15, 15, 34, 36, 40, 36, 40, 35, 35, 37, 37, 39, 39, 38, 38},
+
+ // value table
+ { 1, -1, 0, 2, -2, 0, 3, -3, 1, -1, 4, -4, 5, -5, 1, -1,
+ 6, -6, 2, -2, 7, -7, 1, -1, 8, -8, 9, -9, 3, -3, 1, -1,
+ 10, -10, 2, -2, 11, -11, 1, -1, 12, 4, -12, -4, 1, -1, 13, -13,
+ 1, -1, 14, -14, 2, 5, 15, -2, -5, -15, -3, 3, 16, -16, 17, 1,
+ -1, -17, 6, 18, -6, -18, 2, -2, 19, -19, 1, -1, 20, -20, 4, -4,
+ 7, -7, 21, -21, 1, -1, 2, 3, -3, 22, -2, -22, 8, 23, -8, 1,
+ 2, -23, -1, 2, -2, -2, 24, 1, -24, -1, 25, 5, -5, 1, -25, -1,
+ 9, -9, 26, 1, -26, 3, 1, -1, 27, -3, -1, -27, 1, 3, -1, -3,
+ 28, -4, 4, 10, -10, -28, 1, -1, 1, -1, 29, 6, -29, -6, 30, -4,
+ 3, 3, -3, -30, 1, 4, -1, 31, -3, 1, 11, -11, -1, -31, 32, -1,
+ -1, 2, -2, 1, 1, -32, 1, 4, -1, -4, 33, -1, 1, 1, -1, 5,
+ 5, -5, -33, -1, -12, 12, -5, -7, 1, 1, 7, 34, 4, -4, -1, 4,
+ -34, -4, 35, 36, -2, -35, -2, -36, 2, 13, 2, -1, 1, -13, 1, -1,
+ 37, 1, -5, 6, 5, -1, 38, -6, -8, 5, 8, -1, 1, 1, -37, -1,
+ 5, 39, -5, -5, 6, -6, -38, -39, -14, 40, 14, 2, 1, 1, -2, -40,
+ -1, -2, 2, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1}
+},{
+ // MapTab1
+ 0, // _eobSym
+ 38, // _escSym
+ // run table
+ {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 8, 6, 8, 7,
+ 7, 9, 9, 10, 10, 11, 11, 1, 12, 1, 12, 13, 13, 16, 14, 16,
+ 14, 15, 15, 17, 17, 18, 0, 18, 19, 20, 21, 19, 22, 21, 20, 22,
+ 25, 24, 2, 25, 24, 23, 23, 2, 26, 28, 26, 28, 29, 27, 29, 27,
+ 33, 33, 1, 32, 1, 3, 32, 30, 36, 3, 36, 30, 31, 31, 35, 34,
+ 37, 41, 34, 35, 37, 4, 41, 4, 49, 8, 8, 49, 40, 38, 5, 38,
+ 40, 39, 5, 39, 42, 43, 42, 7, 57, 6, 43, 44, 6, 50, 7, 44,
+ 57, 48, 50, 48, 45, 45, 46, 47, 51, 46, 47, 58, 1, 51, 58, 1,
+ 52, 59, 53, 9, 52, 55, 55, 59, 53, 56, 54, 56, 54, 9, 64, 64,
+ 60, 63, 60, 63, 61, 62, 61, 62, 2, 10, 2, 10, 11, 1, 11, 13,
+ 12, 1, 12, 13, 16, 16, 8, 8, 14, 3, 3, 15, 14, 15, 4, 4,
+ 1, 17, 17, 5, 1, 7, 7, 5, 6, 1, 2, 2, 6, 22, 1, 25,
+ 21, 22, 8, 24, 1, 21, 25, 24, 8, 18, 18, 23, 9, 20, 23, 33,
+ 29, 33, 20, 1, 19, 1, 29, 36, 9, 36, 19, 41, 28, 57, 32, 3,
+ 28, 3, 1, 27, 49, 49, 1, 32, 26, 26, 2, 4, 4, 7, 57, 41,
+ 2, 7, 10, 5, 37, 16, 10, 27, 8, 8, 13, 16, 37, 13, 1, 5},
+
+ // value table
+ {0, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1,
+ -1, 1, -1, 1, -1, 1, -1, 2, 1, -2, -1, 1, -1, 1, 1, -1,
+ -1, 1, -1, 1, -1, 1, 0, -1, 1, 1, 1, -1, 1, -1, -1, -1,
+ 1, 1, 2, -1, -1, 1, -1, -2, 1, 1, -1, -1, 1, 1, -1, -1,
+ 1, -1, 3, 1, -3, 2, -1, 1, 1, -2, -1, -1, -1, 1, 1, 1,
+ 1, 1, -1, -1, -1, 2, -1, -2, 1, 2, -2, -1, 1, 1, 2, -1,
+ -1, 1, -2, -1, 1, 1, -1, 2, 1, 2, -1, 1, -2, -1, -2, -1,
+ -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 4, -1, -1, -4,
+ 1, 1, 1, 2, -1, -1, 1, -1, -1, 1, -1, -1, 1, -2, 1, -1,
+ 1, 1, -1, -1, 1, 1, -1, -1, 3, 2, -3, -2, 2, 5, -2, 2,
+ 2, -5, -2, -2, -2, 2, -3, 3, 2, 3, -3, 2, -2, -2, 3, -3,
+ 6, 2, -2, 3, -6, 3, -3, -3, 3, 7, -4, 4, -3, 2, -7, 2,
+ 2, -2, -4, 2, 8, -2, -2, -2, 4, 2, -2, 2, 3, 2, -2, -2,
+ 2, 2, -2, -8, -2, 9, -2, 2, -3, -2, 2, -2, 2, 2, 2, 4,
+ -2, -4, 10, 2, 2, -2, -9, -2, 2, -2, 5, 4, -4, 4, -2, 2,
+ -5, -4, -3, 4, 2, -3, 3, -2, -5, 5, 3, 3, -2, -3, -10, -4}
+},{
+ // MapTab2
+ 2, // _eobSym
+ 11, // _escSym
+ // run table
+ {1, 1, 0, 2, 2, 1, 1, 3, 3, 4, 4, 0, 1, 1, 5, 5,
+ 2, 2, 6, 6, 7, 7, 1, 8, 1, 8, 3, 3, 9, 9, 1, 2,
+ 2, 1, 4, 10, 4, 10, 11, 11, 1, 5, 12, 12, 1, 5, 13, 13,
+ 3, 3, 6, 6, 2, 2, 14, 14, 16, 16, 15, 7, 15, 8, 8, 7,
+ 1, 1, 17, 17, 4, 4, 1, 1, 18, 18, 2, 2, 5, 5, 25, 3,
+ 9, 3, 25, 9, 19, 24, 19, 24, 1, 21, 20, 1, 21, 22, 20, 22,
+ 23, 23, 8, 6, 33, 6, 8, 33, 7, 7, 26, 26, 1, 32, 1, 32,
+ 28, 4, 28, 10, 29, 27, 27, 10, 41, 4, 29, 2, 2, 41, 36, 31,
+ 49, 31, 34, 30, 34, 36, 30, 35, 1, 49, 11, 5, 35, 11, 1, 3,
+ 3, 5, 37, 37, 8, 40, 8, 40, 12, 12, 42, 42, 1, 38, 16, 57,
+ 1, 6, 16, 39, 38, 6, 7, 7, 13, 13, 39, 43, 2, 43, 57, 2,
+ 50, 9, 44, 9, 50, 4, 15, 48, 44, 4, 1, 15, 48, 14, 14, 1,
+ 45, 45, 8, 3, 5, 8, 51, 47, 3, 46, 46, 47, 5, 51, 1, 17,
+ 17, 58, 1, 58, 2, 52, 52, 2, 53, 7, 59, 6, 6, 56, 53, 55,
+ 7, 55, 1, 54, 59, 56, 54, 10, 1, 10, 4, 60, 1, 60, 8, 4,
+ 8, 64, 64, 61, 1, 63, 3, 63, 62, 61, 5, 11, 5, 3, 11, 62},
+
+ // value table
+ { 1, -1, 0, 1, -1, 2, -2, 1, -1, 1, -1, 0, 3, -3, 1, -1,
+ 2, -2, 1, -1, 1, -1, 4, 1, -4, -1, 2, -2, 1, -1, 5, 3,
+ -3, -5, 2, 1, -2, -1, 1, -1, 6, 2, 1, -1, -6, -2, 1, -1,
+ 3, -3, 2, -2, 4, -4, 1, -1, 1, -1, 1, 2, -1, 2, -2, -2,
+ 7, -7, 1, -1, 3, -3, 8, -8, 1, -1, 5, -5, 3, -3, 1, 4,
+ 2, -4, -1, -2, 1, 1, -1, -1, 9, 1, 1, -9, -1, 1, -1, -1,
+ 1, -1, 3, -3, 1, 3, -3, -1, 3, -3, 1, -1, 10, 1, -10, -1,
+ 1, 4, -1, 2, 1, -1, 1, -2, 1, -4, -1, 6, -6, -1, 1, 1,
+ 1, -1, 1, 1, -1, -1, -1, 1, 11, -1, -2, 4, -1, 2, -11, 5,
+ -5, -4, -1, 1, 4, 1, -4, -1, -2, 2, 1, -1, 12, 1, -2, 1,
+ -12, 4, 2, 1, -1, -4, 4, -4, 2, -2, -1, 1, 7, -1, -1, -7,
+ -1, -3, 1, 3, 1, 5, 2, 1, -1, -5, 13, -2, -1, 2, -2, -13,
+ 1, -1, 5, 6, 5, -5, 1, 1, -6, 1, -1, -1, -5, -1, 14, 2,
+ -2, 1, -14, -1, 8, 1, -1, -8, 1, 5, 1, 5, -5, 1, -1, 1,
+ -5, -1, 15, 1, -1, -1, -1, 3, -15, -3, 6, 1, 16, -1, 6, -6,
+ -6, 1, -1, 1, -16, 1, 7, -1, 1, -1, -6, -3, 6, -7, 3, -1}
+},{
+ // MapTab3
+ 0, // _eobSym
+ 35, // _escSym
+ // run table
+ {0, 1, 1, 2, 2, 3, 3, 4, 4, 1, 1, 5, 5, 6, 6, 7,
+ 7, 8, 8, 9, 9, 2, 2, 10, 10, 1, 1, 11, 11, 12, 12, 3,
+ 3, 13, 13, 0, 14, 14, 16, 15, 16, 15, 4, 4, 17, 1, 17, 1,
+ 5, 5, 18, 18, 2, 2, 6, 6, 8, 19, 7, 8, 7, 19, 20, 20,
+ 21, 21, 22, 24, 22, 24, 23, 23, 1, 1, 25, 25, 3, 3, 26, 26,
+ 9, 9, 27, 27, 28, 28, 33, 29, 4, 33, 29, 1, 4, 1, 32, 32,
+ 2, 2, 31, 10, 30, 10, 30, 31, 34, 34, 5, 5, 36, 36, 35, 41,
+ 35, 11, 41, 11, 37, 1, 8, 8, 37, 6, 1, 6, 40, 7, 7, 40,
+ 12, 38, 12, 39, 39, 38, 49, 13, 49, 13, 3, 42, 3, 42, 16, 16,
+ 43, 43, 14, 14, 1, 1, 44, 15, 44, 15, 2, 2, 57, 48, 50, 48,
+ 57, 50, 4, 45, 45, 4, 46, 47, 47, 46, 1, 51, 1, 17, 17, 51,
+ 8, 9, 9, 5, 58, 8, 58, 5, 52, 52, 55, 56, 53, 56, 55, 59,
+ 59, 53, 54, 1, 6, 54, 7, 7, 6, 1, 2, 3, 2, 3, 64, 60,
+ 60, 10, 10, 64, 61, 62, 61, 63, 1, 63, 62, 1, 18, 24, 18, 4,
+ 25, 4, 8, 21, 21, 1, 24, 22, 25, 22, 8, 11, 19, 11, 23, 1,
+ 20, 23, 19, 20, 5, 12, 5, 1, 16, 2, 12, 13, 2, 13, 1, 16},
+
+ // value table
+ { 0, 1, -1, 1, -1, 1, -1, 1, -1, 2, -2, 1, -1, 1, -1, 1,
+ -1, 1, -1, 1, -1, 2, -2, 1, -1, 3, -3, 1, -1, 1, -1, 2,
+ -2, 1, -1, 0, 1, -1, 1, 1, -1, -1, 2, -2, 1, 4, -1, -4,
+ 2, -2, 1, -1, -3, 3, 2, -2, 2, 1, 2, -2, -2, -1, 1, -1,
+ 1, -1, 1, 1, -1, -1, 1, -1, 5, -5, 1, -1, 3, -3, 1, -1,
+ 2, -2, 1, -1, 1, -1, 1, 1, 3, -1, -1, 6, -3, -6, -1, 1,
+ 4, -4, 1, 2, 1, -2, -1, -1, 1, -1, 3, -3, 1, -1, 1, 1,
+ -1, 2, -1, -2, 1, 7, -3, 3, -1, 3, -7, -3, 1, -3, 3, -1,
+ 2, 1, -2, 1, -1, -1, 1, 2, -1, -2, -4, -1, 4, 1, 2, -2,
+ 1, -1, -2, 2, 8, -8, -1, 2, 1, -2, -5, 5, 1, -1, -1, 1,
+ -1, 1, 4, -1, 1, -4, -1, -1, 1, 1, 9, 1, -9, 2, -2, -1,
+ -4, 3, -3, -4, -1, 4, 1, 4, 1, -1, 1, -1, 1, 1, -1, 1,
+ -1, -1, -1, 10, 4, 1, 4, -4, -4, -10, 6, 5, -6, -5, 1, -1,
+ 1, 3, -3, -1, 1, -1, -1, -1, 11, 1, 1, -11, -2, -2, 2, 5,
+ -2, -5, -5, 2, -2, 12, 2, -2, 2, 2, 5, -3, -2, 3, -2, -12,
+ -2, 2, 2, 2, -5, 3, 5, 13, -3, 7, -3, -3, -7, 3, -13, 3}
+},{
+ // MapTab4
+ 0, // _eobSym
+ 34, // _escSym
+ // run table
+ {0, 1, 1, 1, 2, 2, 1, 3, 3, 1, 1, 1, 4, 4, 1, 5,
+ 2, 1, 5, 2, 1, 1, 6, 6, 1, 1, 1, 1, 1, 7, 3, 1,
+ 2, 3, 0, 1, 2, 7, 1, 1, 1, 8, 1, 1, 8, 1, 1, 1,
+ 9, 1, 9, 1, 2, 1, 1, 2, 1, 1, 10, 4, 1, 10, 1, 4,
+ 1, 1, 1, 1, 1, 3, 1, 1, 1, 3, 2, 1, 5, 1, 1, 1,
+ 2, 5, 1, 11, 1, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 1, 6, 1, 6, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 12,
+ 3, 1, 12, 1, 1, 1, 2, 1, 1, 3, 1, 1, 1, 1, 1, 1,
+ 4, 1, 1, 1, 2, 1, 1, 4, 1, 1, 1, 1, 1, 1, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 2, 1, 1, 5,
+ 1, 1, 1, 1, 1, 7, 1, 7, 1, 1, 2, 3, 1, 1, 1, 1,
+ 5, 1, 1, 1, 1, 1, 1, 2, 13, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 13, 2, 1, 1, 4, 1, 1, 1,
+ 3, 1, 6, 1, 1, 1, 14, 1, 1, 1, 1, 1, 14, 6, 1, 1,
+ 1, 1, 15, 2, 4, 1, 2, 3, 15, 1, 1, 1, 8, 1, 1, 8,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1},
+
+ // value table
+ { 0, 1, -1, 2, 1, -1, -2, 1, -1, 3, -3, 4, 1, -1, -4, 1,
+ 2, 5, -1, -2, -5, 6, 1, -1, -6, 7, -7, 8, -8, 1, 2, 9,
+ 3, -2, 0, -9, -3, -1, 10, -10, 11, 1, -11, 12, -1, -12, 13, -13,
+ 1, 14, -1, -14, 4, 15, -15, -4, 16, -16, 1, 2, 17, -1, -17, -2,
+ 18, -18, 19, -19, 20, 3, -20, 21, -21, -3, 5, 22, 2, -22, -23, 23,
+ -5, -2, 24, 1, -24, -1, 25, -25, 26, -26, -27, 27, 28, 29, -28, -29,
+ 6, 30, 2, -31, -2, -30, 31, -6, -32, 32, 33, -33, 34, -35, -34, 1,
+ 4, -36, -1, 35, 37, 36, 7, -37, 38, -4, -38, 39, 41, 40, -40, -39,
+ 3, 42, -43, -41, -7, -42, 43, -3, 44, -44, 45, -45, 46, 47, 8, -47,
+ -48, -46, 50, -50, 48, 49, 51, -49, 52, -52, 5, -51, -8, -53, 53, 3,
+ -56, 56, 55, 54, -54, 2, 60, -2, -55, 58, 9, -5, 59, 57, -57, -63,
+ -3, -58, -60, -61, 61, -59, -62, -9, 1, 64, 62, 69, -64, 63, 65, -67,
+ -68, 66, -65, 68, -66, -69, 67, -70, -1, 10, 71, -71, 4, 73, 72, 70,
+ 6, -76, -3, 74, -78, -74, 1, 78, 80, -72, -75, 76, -1, 3, -73, 79,
+ 75, 77, 1, 11, -4, -79, -10, -6, -1, -77, -83, -80, 2, 81, -84, -2,
+ 83, -81, 82, -82, 84, -87, -86, 85, -11, -85, 86, -89, 87, -88, 88, 89}
+},{
+ // MapTab5
+ 2, // _eobSym
+ 33, // _escSym
+ // run table
+ {1, 1, 0, 2, 1, 2, 1, 3, 3, 1, 1, 4, 4, 2, 2, 1,
+ 1, 5, 5, 6, 1, 6, 1, 7, 7, 3, 3, 2, 8, 2, 8, 1,
+ 1, 0, 9, 9, 1, 1, 10, 4, 10, 4, 11, 11, 2, 1, 2, 1,
+ 12, 12, 3, 3, 1, 1, 13, 5, 5, 13, 14, 1, 1, 14, 2, 2,
+ 6, 6, 15, 1, 1, 15, 16, 4, 7, 16, 4, 7, 1, 1, 3, 3,
+ 8, 8, 2, 2, 1, 1, 17, 17, 1, 1, 18, 18, 5, 5, 2, 2,
+ 1, 1, 9, 19, 9, 19, 20, 3, 3, 20, 1, 10, 21, 1, 10, 4,
+ 4, 21, 22, 6, 6, 22, 1, 1, 23, 24, 2, 2, 23, 24, 11, 1,
+ 1, 11, 7, 25, 7, 1, 1, 25, 8, 8, 3, 26, 3, 1, 12, 2,
+ 2, 26, 1, 12, 5, 5, 27, 4, 1, 4, 1, 27, 28, 1, 28, 13,
+ 1, 13, 2, 29, 2, 1, 32, 6, 1, 30, 14, 29, 14, 6, 3, 31,
+ 3, 1, 30, 1, 32, 31, 33, 9, 33, 1, 1, 7, 9, 7, 2, 2,
+ 1, 1, 4, 36, 34, 4, 5, 10, 10, 5, 34, 1, 1, 35, 8, 8,
+ 36, 3, 35, 1, 15, 3, 2, 1, 16, 15, 16, 2, 37, 1, 37, 1,
+ 1, 1, 6, 6, 38, 1, 38, 11, 1, 39, 39, 40, 11, 2, 41, 4,
+ 40, 1, 2, 4, 1, 1, 1, 41, 3, 1, 3, 1, 5, 7, 5, 7},
+
+ // value table
+ { 1, -1, 0, 1, 2, -1, -2, 1, -1, 3, -3, 1, -1, 2, -2, 4,
+ -4, 1, -1, 1, 5, -1, -5, 1, -1, 2, -2, 3, 1, -3, -1, 6,
+ -6, 0, 1, -1, 7, -7, 1, 2, -1, -2, 1, -1, 4, 8, -4, -8,
+ 1, -1, 3, -3, 9, -9, 1, 2, -2, -1, 1, 10, -10, -1, 5, -5,
+ 2, -2, 1, 11, -11, -1, 1, 3, 2, -1, -3, -2, 12, -12, 4, -4,
+ 2, -2, -6, 6, 13, -13, 1, -1, 14, -14, 1, -1, 3, -3, 7, -7,
+ 15, -15, 2, 1, -2, -1, 1, 5, -5, -1, -16, 2, 1, 16, -2, 4,
+ -4, -1, 1, 3, -3, -1, 17, -17, 1, 1, -8, 8, -1, -1, 2, 18,
+ -18, -2, 3, 1, -3, 19, -19, -1, 3, -3, 6, 1, -6, 20, 2, 9,
+ -9, -1, -20, -2, 4, -4, 1, -5, 21, 5, -21, -1, 1, -22, -1, 2,
+ 22, -2, 10, 1, -10, 23, 1, 4, -23, 1, 2, -1, -2, -4, -7, 1,
+ 7, -24, -1, 24, -1, -1, 1, 3, -1, -25, 25, 4, -3, -4, 11, -11,
+ 26, -26, 6, 1, 1, -6, -5, -3, 3, 5, -1, -27, 27, 1, 4, -4,
+ -1, -8, -1, 28, 2, 8, -12, -28, -2, -2, 2, 12, -1, 29, 1, -29,
+ 30, -30, 5, -5, 1, -31, -1, 3, 31, -1, 1, 1, -3, -13, 1, -7,
+ -1, -32, 13, 7, 32, 33, -33, -1, -9, -34, 9, 34, -6, 5, 6, -5}
+},{
+ // MapTab6
+ 2, // _eobSym
+ 13, // _escSym
+ // run table
+ {1, 1, 0, 1, 1, 2, 2, 1, 1, 3, 3, 1, 1, 0, 2, 2,
+ 4, 1, 4, 1, 1, 1, 5, 5, 1, 1, 6, 6, 2, 2, 1, 1,
+ 3, 3, 7, 7, 1, 1, 8, 8, 1, 1, 2, 2, 1, 9, 1, 9,
+ 4, 4, 10, 1, 1, 10, 1, 1, 11, 11, 3, 3, 1, 2, 1, 2,
+ 1, 1, 12, 12, 5, 5, 1, 1, 13, 1, 1, 13, 2, 2, 1, 1,
+ 6, 6, 1, 1, 4, 14, 4, 14, 3, 1, 3, 1, 1, 1, 15, 7,
+ 15, 2, 2, 7, 1, 1, 1, 8, 1, 8, 16, 16, 1, 1, 1, 1,
+ 2, 1, 1, 2, 1, 1, 3, 5, 5, 3, 4, 1, 1, 4, 1, 1,
+ 17, 17, 9, 1, 1, 9, 2, 2, 1, 1, 10, 10, 1, 6, 1, 1,
+ 6, 18, 1, 1, 18, 1, 1, 1, 2, 2, 3, 1, 3, 1, 1, 1,
+ 4, 1, 19, 1, 19, 7, 1, 1, 20, 1, 4, 20, 1, 7, 11, 2,
+ 1, 11, 21, 2, 8, 5, 1, 8, 1, 5, 21, 1, 1, 1, 22, 1,
+ 1, 22, 1, 1, 3, 3, 1, 23, 2, 12, 24, 1, 1, 2, 1, 1,
+ 12, 23, 1, 1, 24, 1, 1, 1, 4, 1, 1, 1, 2, 1, 6, 6,
+ 4, 2, 1, 1, 1, 1, 1, 1, 1, 14, 13, 3, 1, 25, 9, 25,
+ 14, 1, 9, 3, 13, 1, 1, 1, 1, 1, 10, 1, 1, 2, 10, 2},
+
+ // value table
+ {-20, -1, 0, 2, -2, 1, -1, 3, -3, 1, -1, 4, -4, 0, 2, -2,
+ 1, 5, -1, -5, 6, -6, 1, -1, 7, -7, 1, -1, 3, -3, 8, -8,
+ 2, -2, 1, -1, 9, -9, 1, -1, 10, -10, 4, -4, 11, 1, -11, -1,
+ 2, -2, 1, 12, -12, -1, 13, -13, 1, -1, 3, -3, 14, 5, -14, -5,
+ -15, 15, -1, 1, 2, -2, 16, -16, 1, 17, -17, -1, 6, -6, 18, -18,
+ 2, -2, -19, 19, -3, 1, 3, -1, 4, 20, -4, 1, -21, 21, 1, 2,
+ -1, -7, 7, -2, 22, -22, 23, 2, -23, -2, 1, -1, -24, 24, -25, 25,
+ -8, -26, 26, 8, -27, 27, 5, 3, -3, -5, -4, 28, -28, 4, 29, -29,
+ 1, -1, -2, -30, 30, 2, 9, -9, -31, 31, 2, -2, -32, 3, 32, -33,
+ -3, 1, 33, -34, -1, 34, -35, 35, -10, 10, -6, 36, 6, -36, 37, -37,
+ -5, 38, 1, -38, -1, 3, 39, -39, -1, 40, 5, 1, -40, -3, 2, -11,
+ -41, -2, 1, 11, -3, -4, 41, 3, 42, 4, -1, -43, -42, 43, 1, -44,
+ 45, -1, 44, -45, -7, 7, -46, 1, -12, 2, 1, -47, 46, 12, 47, 48,
+ -2, -1, -48, 49, -1, -50, -49, 50, -6, -51, 51, 52, -13, 53, -4, 4,
+ 6, 13, -53, -52, -54, 55, 54, -55, -56, -2, 2, -8, 56, 1, -3, -1,
+ 2, 58, 3, 8, -2, 57, -58, -60, -59, -57, -3, 60, 59, -14, 3, 14}
+},{
+ // MapTab7
+ 2, // _eobSym
+ 38, // _escSym
+ // run table
+ {1, 1, 0, 2, 2, 1, 1, 3, 3, 4, 4, 5, 5, 1, 1, 6,
+ 6, 2, 2, 7, 7, 8, 8, 1, 1, 3, 3, 9, 9, 10, 10, 1,
+ 1, 2, 2, 4, 4, 11, 0, 11, 12, 12, 13, 13, 1, 1, 5, 5,
+ 14, 14, 15, 16, 15, 16, 3, 3, 1, 6, 1, 6, 2, 2, 7, 7,
+ 8, 8, 17, 17, 1, 1, 4, 4, 18, 18, 2, 2, 1, 19, 1, 20,
+ 19, 20, 21, 21, 3, 3, 22, 22, 5, 5, 24, 1, 1, 23, 9, 23,
+ 24, 9, 2, 2, 10, 1, 1, 10, 6, 6, 25, 4, 4, 25, 7, 7,
+ 26, 8, 1, 8, 3, 1, 26, 3, 11, 11, 27, 27, 2, 28, 1, 2,
+ 28, 1, 12, 12, 5, 5, 29, 13, 13, 29, 32, 1, 1, 33, 31, 30,
+ 32, 4, 30, 33, 4, 31, 3, 14, 1, 1, 3, 34, 34, 2, 2, 14,
+ 6, 6, 35, 36, 35, 36, 1, 15, 1, 16, 16, 15, 7, 9, 7, 9,
+ 37, 8, 8, 37, 1, 1, 39, 2, 38, 39, 2, 40, 5, 38, 40, 5,
+ 3, 3, 4, 4, 10, 10, 1, 1, 1, 1, 41, 2, 41, 2, 6, 6,
+ 1, 1, 11, 42, 11, 43, 3, 42, 3, 17, 4, 43, 1, 17, 7, 1,
+ 8, 44, 4, 7, 44, 5, 8, 2, 5, 1, 2, 48, 45, 1, 12, 45,
+ 12, 48, 13, 13, 1, 9, 9, 46, 1, 46, 47, 47, 49, 18, 18, 49},
+
+ // value table
+ { 1, -1, 0, 1, -1, 2, -2, 1, -1, 1, -1, 1, -1, 3, -3, 1,
+ -1, -2, 2, 1, -1, 1, -1, 4, -4, -2, 2, 1, -1, 1, -1, 5,
+ -5, -3, 3, 2, -2, 1, 0, -1, 1, -1, 1, -1, 6, -6, 2, -2,
+ 1, -1, 1, 1, -1, -1, -3, 3, 7, 2, -7, -2, -4, 4, 2, -2,
+ 2, -2, 1, -1, 8, -8, 3, -3, 1, -1, -5, 5, 9, 1, -9, 1,
+ -1, -1, 1, -1, -4, 4, 1, -1, 3, -3, 1, -10, 10, 1, 2, -1,
+ -1, -2, 6, -6, 2, 11, -11, -2, 3, -3, 1, -4, 4, -1, 3, -3,
+ 1, 3, 12, -3, -5, -12, -1, 5, 2, -2, 1, -1, -7, 1, 13, 7,
+ -1, -13, 2, -2, 4, -4, 1, 2, -2, -1, 1, 14, -14, 1, 1, 1,
+ -1, -5, -1, -1, 5, -1, -6, 2, -15, 15, 6, 1, -1, -8, 8, -2,
+ -4, 4, 1, 1, -1, -1, 16, 2, -16, -2, 2, -2, 4, 3, -4, -3,
+ -1, -4, 4, 1, -17, 17, -1, -9, 1, 1, 9, 1, -5, -1, -1, 5,
+ -7, 7, 6, -6, 3, -3, 18, -18, 19, -19, 1, -10, -1, 10, -5, 5,
+ 20, -20, -3, 1, 3, 1, 8, -1, -8, 2, 7, -1, -21, -2, 5, 21,
+ 5, -1, -7, -5, 1, -6, -5, -11, 6, 22, 11, 1, 1, -22, -3, -1,
+ 3, -1, 3, -3, -23, 4, -4, 1, 23, -1, 1, -1, 1, -2, 2, -1}
+},{
+ // MapTab8
+ 4, // _eobSym
+ 11, // _escSym
+ // run table
+ {1, 1, 1, 1, 0, 2, 2, 1, 1, 3, 3, 0, 1, 1, 2, 2,
+ 4, 4, 1, 1, 5, 5, 1, 1, 2, 2, 3, 3, 6, 6, 1, 1,
+ 7, 7, 8, 1, 8, 2, 2, 1, 4, 4, 1, 3, 1, 3, 9, 9,
+ 2, 2, 1, 5, 1, 5, 10, 10, 1, 1, 11, 11, 3, 6, 3, 4,
+ 4, 6, 2, 2, 1, 12, 1, 12, 7, 13, 7, 13, 1, 1, 8, 8,
+ 2, 2, 14, 14, 16, 15, 16, 5, 5, 1, 3, 15, 1, 3, 4, 4,
+ 1, 1, 17, 17, 2, 2, 6, 6, 1, 18, 1, 18, 22, 21, 22, 21,
+ 25, 24, 25, 19, 9, 20, 9, 23, 19, 24, 20, 3, 23, 7, 3, 1,
+ 1, 7, 28, 26, 29, 5, 28, 26, 5, 8, 29, 4, 8, 27, 2, 2,
+ 4, 27, 1, 1, 10, 36, 10, 33, 33, 36, 30, 1, 32, 32, 1, 30,
+ 6, 31, 31, 35, 3, 6, 11, 11, 3, 2, 35, 2, 34, 1, 34, 1,
+ 37, 37, 12, 7, 12, 5, 41, 5, 4, 7, 1, 8, 13, 4, 1, 41,
+ 13, 38, 8, 38, 9, 1, 40, 40, 9, 1, 39, 2, 2, 49, 39, 42,
+ 3, 3, 14, 16, 49, 14, 16, 42, 43, 43, 6, 6, 15, 1, 1, 15,
+ 44, 44, 1, 1, 50, 48, 4, 5, 4, 7, 5, 2, 10, 10, 48, 7,
+ 50, 45, 2, 1, 45, 8, 8, 1, 46, 46, 3, 47, 47, 3, 1, 1},
+
+ // value table
+ { 1, -1, 2, -2, 0, 1, -1, 3, -3, 1, -1, 0, 4, -4, 2, -2,
+ 1, -1, 5, -5, 1, -1, 6, -6, 3, -3, 2, -2, 1, -1, 7, -7,
+ 1, -1, 1, 8, -1, 4, -4, -8, 2, -2, 9, 3, -9, -3, 1, -1,
+ 5, -5, 10, 2, -10, -2, 1, -1, 11, -11, 1, -1, -4, 2, 4, 3,
+ -3, -2, 6, -6, 12, 1, -12, -1, 2, 1, -2, -1, 13, -13, 2, -2,
+ 7, -7, 1, -1, 1, 1, -1, 3, -3, 14, 5, -1, -14, -5, 4, -4,
+ 15, -15, 1, -1, 8, -8, -3, 3, 16, 1, -16, -1, 1, 1, -1, -1,
+ 1, 1, -1, 1, 2, 1, -2, 1, -1, -1, -1, 6, -1, 3, -6, 17,
+ -17, -3, 1, 1, 1, 4, -1, -1, -4, 3, -1, 5, -3, -1, -9, 9,
+ -5, 1, 18, -18, 2, 1, -2, 1, -1, -1, 1, 19, -1, 1, -19, -1,
+ 4, 1, -1, 1, 7, -4, -2, 2, -7, 10, -1, -10, 1, 20, -1, -20,
+ 1, -1, 2, 4, -2, 5, 1, -5, 6, -4, 21, 4, 2, -6, -21, -1,
+ -2, 1, -4, -1, -3, 22, -1, 1, 3, -22, -1, 11, -11, 1, 1, 1,
+ 8, -8, 2, 2, -1, -2, -2, -1, 1, -1, -5, 5, 2, 23, -23, -2,
+ 1, -1, 24, -24, -1, -1, 7, 6, -7, 5, -6, 12, -3, 3, 1, -5,
+ 1, 1, -12, 25, -1, -5, 5, -25, -1, 1, 9, 1, -1, -9, 26, -26}
+}
+};
+
+} // End of namespace Indeo
+} // End of namespace Image
diff --git a/image/codecs/indeo/indeo.h b/image/codecs/indeo/indeo.h
new file mode 100644
index 0000000000..3b0b1854f5
--- /dev/null
+++ b/image/codecs/indeo/indeo.h
@@ -0,0 +1,584 @@
+/* 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"
+#include "graphics/managed_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
+
+ 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;
+
+ 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 ivi_decode_coded_blocks(GetBits *gb, IVIBandDesc *band,
+ IviMCFunc mc, IviMCAvgFunc mcAvg, int mvX, int mvY,
+ int mvX2, int mvY2, int *prevDc, int isIntra,
+ int mcType, int mcType2, uint32 quant, int offs);
+
+ int ivi_dc_transform(IVIBandDesc *band, int *prevDc, int bufOffs,
+ int blkSize);
+protected:
+ IVI45DecContext _ctx;
+ Graphics::PixelFormat _pixelFormat;
+ Graphics::ManagedSurface *_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
+ */
+ virtual Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; }
+
+ /**
+ * 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 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);
+ virtual ~IndeoDecoderBase();
+};
+
+} // End of namespace Indeo
+} // End of namespace Image
+
+#endif
diff --git a/image/codecs/indeo/indeo_dsp.cpp b/image/codecs/indeo/indeo_dsp.cpp
new file mode 100644
index 0000000000..15626e9473
--- /dev/null
+++ b/image/codecs/indeo/indeo_dsp.cpp
@@ -0,0 +1,644 @@
+/* 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.
+ *
+ */
+
+/* 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) {
+ int i, shift, sp1, sp2, sp3, sp4;
+ const int32 *src;
+ int32 * dst;
+ int tmp[64];
+ int t0, t1, t2, t3, t4, t5, t6, t7, t8;
+
+ // apply the InvHaar8 to all columns
+#define COMPENSATE(x) (x)
+ src = in;
+ dst = tmp;
+ for (i = 0; i < 8; i++) {
+ if (flags[i]) {
+ // pre-scaling
+ shift = !(i & 4);
+ sp1 = src[ 0] << shift;
+ sp2 = src[ 8] << shift;
+ sp3 = src[16] << shift;
+ 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 (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 i;
+ int t0, t1, t2, t3, t4, t5, t6, t7, t8;
+
+ // apply the InvHaar8 to all rows
+#define COMPENSATE(x) (x)
+ for (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 i;
+ int t0, t1, t2, t3, t4, t5, t6, t7, t8;
+
+ // apply the InvHaar8 to all columns
+#define COMPENSATE(x) (x)
+ for (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) {
+ int i, shift, sp1, sp2;
+ const int32 *src;
+ int32 * dst;
+ int tmp[16];
+ int t0, t1, t2, t3, t4;
+
+ // apply the InvHaar4 to all columns
+#define COMPENSATE(x) (x)
+ src = in;
+ dst = tmp;
+ for (i = 0; i < 4; i++) {
+ if (flags[i]) {
+ // pre-scaling
+ shift = !(i & 2);
+ sp1 = src[0] << shift;
+ 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 (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 i;
+ int t0, t1, t2, t3, t4;
+
+ // apply the InvHaar4 to all rows
+#define COMPENSATE(x) (x)
+ for (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 i;
+ int t0, t1, t2, t3, t4;
+
+ // apply the InvHaar8 to all columns
+#define COMPENSATE(x) (x)
+ for (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) {
+ int x, y;
+ int16 dcCoeff;
+
+ dcCoeff = (*in + 0) >> 3;
+
+ for (y = 0; y < blkSize; out += pitch, y++) {
+ for (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) {
+ int i;
+ const int32 *src;
+ int32 * dst;
+ int tmp[64];
+ int t0, t1, t2, t3, t4, t5, t6, t7, t8;
+
+#define COMPENSATE(x) (x)
+ src = in;
+ dst = tmp;
+ for (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 (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) {
+ int i;
+ const int32 *src;
+ int32 * dst;
+ int tmp[16];
+ int t0, t1, t2, t3, t4;
+
+#define COMPENSATE(x) (x)
+ src = in;
+ dst = tmp;
+ for (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 (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) {
+ int x, y;
+ int16 dcCoeff;
+
+ dcCoeff = (*in + 1) >> 1;
+
+ for (y = 0; y < blkSize; out += pitch, y++) {
+ for (x = 0; x < blkSize; x++)
+ out[x] = dcCoeff;
+ }
+}
+
+void IndeoDSP::ffIviRowSlant8(const int32 *in, int16 *out, uint32 pitch,
+ const uint8 *flags) {
+ int i;
+ int t0, t1, t2, t3, t4, t5, t6, t7, t8;
+
+#define COMPENSATE(x) (((x) + 1)>>1)
+ for (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) {
+ int x, y;
+ int16 dcCoeff;
+
+ dcCoeff = (*in + 1) >> 1;
+
+ for (x = 0; x < blkSize; x++)
+ out[x] = dcCoeff;
+
+ out += pitch;
+
+ for (y = 1; y < blkSize; out += pitch, y++) {
+ for (x = 0; x < blkSize; x++)
+ out[x] = 0;
+ }
+}
+
+void IndeoDSP::ffIviColSlant8(const int32 *in, int16 *out, uint32 pitch, const uint8 *flags) {
+ int i, row2, row4, row8;
+ int t0, t1, t2, t3, t4, t5, t6, t7, t8;
+
+ row2 = pitch << 1;
+ row4 = pitch << 2;
+ row8 = pitch << 3;
+
+#define COMPENSATE(x) (((x) + 1)>>1)
+ for (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) {
+ int x, y;
+ int16 dcCoeff;
+
+ dcCoeff = (*in + 1) >> 1;
+
+ for (y = 0; y < blkSize; out += pitch, y++) {
+ out[0] = dcCoeff;
+ for (x = 1; x < blkSize; x++)
+ out[x] = 0;
+ }
+}
+
+void IndeoDSP::ffIviRowSlant4(const int32 *in, int16 *out,
+ uint32 pitch, const uint8 *flags) {
+ int i;
+ int t0, t1, t2, t3, t4;
+
+#define COMPENSATE(x) (((x) + 1)>>1)
+ for (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 i, row2;
+ int t0, t1, t2, t3, t4;
+
+ row2 = pitch << 1;
+
+#define COMPENSATE(x) (((x) + 1)>>1)
+ for (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) {
+ int x, y;
+
+ for (y = 0; y < 8; out += pitch, in += 8, y++)
+ for (x = 0; x < 8; x++)
+ out[x] = in[x];
+}
+
+void IndeoDSP::ffIviPutDcPixel8x8(const int32 *in, int16 *out, uint32 pitch,
+ int blkSize) {
+ int y;
+
+ out[0] = in[0];
+ memset(out + 1, 0, 7*sizeof(out[0]));
+ out += pitch;
+
+ for (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) \
+{ \
+ int i, j; \
+ const int16 *wptr; \
+\
+ switch (mcType) { \
+ case 0: /* fullpel (no interpolation) */ \
+ for (i = 0; i < size; i++, buf += dpitch, refBuf += pitch) { \
+ for (j = 0; j < size; j++) {\
+ OP(buf[j], refBuf[j]); \
+ } \
+ } \
+ break; \
+ case 1: /* horizontal halfpel interpolation */ \
+ for (i = 0; i < size; i++, buf += dpitch, refBuf += pitch) \
+ for (j = 0; j < size; j++) \
+ OP(buf[j], (refBuf[j] + refBuf[j+1]) >> 1); \
+ break; \
+ case 2: /* vertical halfpel interpolation */ \
+ wptr = refBuf + pitch; \
+ for (i = 0; i < size; i++, buf += dpitch, wptr += pitch, refBuf += pitch) \
+ for (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 (i = 0; i < size; i++, buf += dpitch, wptr += pitch, refBuf += pitch) \
+ for (j = 0; j < size; j++) \
+ OP(buf[j], (refBuf[j] + refBuf[j+1] + wptr[j] + wptr[j+1]) >> 2); \
+ 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]; \
+ int i, j; \
+\
+ iviMc ## size ##x## size ## NoDelta(tmp, size, refBuf, pitch, mcType); \
+ iviMc ## size ##x## size ## Delta(tmp, size, refBuf2, pitch, mcType2); \
+ for (i = 0; i < size; i++, buf += pitch) { \
+ for (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
diff --git a/image/codecs/indeo/indeo_dsp.h b/image/codecs/indeo/indeo_dsp.h
new file mode 100644
index 0000000000..8ea223b634
--- /dev/null
+++ b/image/codecs/indeo/indeo_dsp.h
@@ -0,0 +1,336 @@
+/* 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.
+ *
+ */
+
+/* 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
diff --git a/image/codecs/indeo/mem.cpp b/image/codecs/indeo/mem.cpp
new file mode 100644
index 0000000000..9db37ec601
--- /dev/null
+++ b/image/codecs/indeo/mem.cpp
@@ -0,0 +1,172 @@
+/* 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.
+ *
+ */
+
+/* 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 *avMallocZ(size_t size) {
+ void *ptr = malloc(size);
+ if (ptr)
+ memset(ptr, 0, size);
+
+ return ptr;
+}
+
+void *avMallocArray(size_t nmemb, size_t size) {
+ assert(size && nmemb < MAX_INTEGER / size);
+ return malloc(nmemb * size);
+}
+
+void *avMallocZArray(size_t nmemb, size_t size) {
+ assert(size && nmemb < MAX_INTEGER / size);
+ return avMallocZ(nmemb * size);
+}
+
+void avFreeP(void *arg) {
+ void **ptr = (void **)arg;
+ free(*ptr);
+ *ptr = nullptr;
+}
+
+static void *avRealloc(void *ptr, size_t size) {
+ return realloc(ptr, size + !size);
+}
+
+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 = avRealloc(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;
+}
+
+uint8 avClipUint8(int a) {
+ if (a & (~0xFF))
+ return (-a) >> 31;
+ else
+ return a;
+}
+
+unsigned avClipUintp2(int a, int p) {
+ if (a & ~((1 << p) - 1))
+ return -a >> 31 & ((1 << p) - 1);
+ else
+ return a;
+}
+
+} // End of namespace Indeo
+} // End of namespace Image
diff --git a/image/codecs/indeo/mem.h b/image/codecs/indeo/mem.h
new file mode 100644
index 0000000000..8e889e5cbf
--- /dev/null
+++ b/image/codecs/indeo/mem.h
@@ -0,0 +1,148 @@
+/* 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"
+
+/* 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
+
+/**
+ * Allocate a memory block with alignment suitable for all memory accesses
+ * (including vectors if available on the CPU) and zero all the bytes of the
+ * block.
+ *
+ * @param size Size in bytes for the memory block to be allocated
+ * @return Pointer to the allocated block, or `NULL` if it cannot be allocated
+ * @see av_malloc()
+ */
+extern void *avMallocZ(size_t size);
+
+/**
+ * Allocate a memory block for an array with av_malloc().
+ *
+ * The allocated memory will have size `size * nmemb` bytes.
+ *
+ * @param nmemb Number of element
+ * @param size Size of a single element
+ * @return Pointer to the allocated block, or `NULL` if the block cannot
+ * be allocated
+ * @see av_malloc()
+ */
+extern void *avMallocArray(size_t nmemb, size_t size);
+
+/**
+ * Allocate a memory block for an array with av_mallocz().
+ *
+ * The allocated memory will have size `size * nmemb` bytes.
+ *
+ * @param nmemb Number of elements
+ * @param size Size of the single element
+ * @return Pointer to the allocated block, or `NULL` if the block cannot
+ * be allocated
+ *
+ * @see av_mallocz()
+ * @see av_malloc_array()
+ */
+extern void *avMallocZArray(size_t nmemb, size_t size);
+
+/**
+ * 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
+ */
+extern uint8 avClipUint8(int 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
+ */
+extern unsigned avClipUintp2(int a, int p);
+
+/**
+* Clip a signed integer value into the amin-amax range.
+* @param a value to clip
+* @param amin minimum value of the clip range
+* @param amax maximum value of the clip range
+* @return clipped value
+*/
+#define av_clip CLIP
+
+extern const uint8 ffZigZagDirect[64];
+
+} // End of namespace Indeo
+} // End of namespace Image
+
+#endif
diff --git a/image/codecs/indeo/vlc.cpp b/image/codecs/indeo/vlc.cpp
new file mode 100644
index 0000000000..5b9e96cd96
--- /dev/null
+++ b/image/codecs/indeo/vlc.cpp
@@ -0,0 +1,336 @@
+/* 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.
+ *
+ */
+
+/* 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) <= 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 *)avMallocArray((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 = (VLCcode *)a, *sb = (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 - (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
diff --git a/image/codecs/indeo/vlc.h b/image/codecs/indeo/vlc.h
new file mode 100644
index 0000000000..a6dd692732
--- /dev/null
+++ b/image/codecs/indeo/vlc.h
@@ -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 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"
+
+/* 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
diff --git a/image/codecs/indeo4.cpp b/image/codecs/indeo4.cpp
new file mode 100644
index 0000000000..3e4c37bbab
--- /dev/null
+++ b/image/codecs/indeo4.cpp
@@ -0,0 +1,951 @@
+/* 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.
+ *
+ */
+
+/* Intel Indeo 4 decompressor, derived from ffmpeg.
+ *
+ * Original copyright note: * Intel Indeo 3 (IV41, IV42, etc.) video decoder for ffmpeg
+ * written, produced, and directed by Alan Smithee
+ */
+
+#include "common/memstream.h"
+#include "common/textconsole.h"
+#include "graphics/yuv_to_rgb.h"
+#include "image/codecs/indeo4.h"
+#include "image/codecs/indeo/indeo_dsp.h"
+#include "image/codecs/indeo/mem.h"
+
+namespace Image {
+
+#define IVI4_PIC_SIZE_ESC 7
+
+Indeo4Decoder::Indeo4Decoder(uint16 width, uint16 height) : IndeoDecoderBase(width, height) {
+ _ctx._isIndeo4 = true;
+ _ctx._refBuf = 1;
+ _ctx._bRefBuf = 3;
+ _ctx._pFrame = new AVFrame();
+}
+
+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(new Common::MemoryReadStream(buffer, 16 * 8), DisposeAfterUse::YES);
+ bool isIndeo4 = gb.getBits(18) == 0x3FFF8;
+
+ return isIndeo4;
+}
+
+const Graphics::Surface *Indeo4Decoder::decodeFrame(Common::SeekableReadStream &stream) {
+ // Not Indeo 4? Fail
+ if (!isIndeo4(stream))
+ return nullptr;
+
+ // Set up the frame data buffer
+ byte *frameData = new byte[stream.size()];
+ stream.read(frameData, stream.size());
+ _ctx._frameData = frameData;
+ _ctx._frameSize = stream.size();
+
+ // Set up the GetBits instance for reading the data
+ _ctx._gb = new GetBits(new Common::MemoryReadStream(_ctx._frameData, _ctx._frameSize * 8));
+
+ // Decode the frame
+ int err = decodeIndeoFrame();
+
+ // Free the bit reader and frame buffer
+ delete _ctx._gb;
+ _ctx._gb = nullptr;
+ delete[] frameData;
+ _ctx._frameData = nullptr;
+ _ctx._frameSize = 0;
+
+ return (err < 0) ? nullptr : &_surface->rawSurface();
+}
+
+int Indeo4Decoder::decodePictureHeader() {
+ int pic_size_indx, i, p;
+ IVIPicConfig picConf;
+
+ if (_ctx._gb->getBits(18) != 0x3FFF8) {
+ warning("Invalid picture start code!");
+ return -1;
+ }
+
+ _ctx._prevFrameType = _ctx._frameType;
+ _ctx._frameType = _ctx._gb->getBits(3);
+ if (_ctx._frameType == 7) {
+ warning("Invalid frame type: %d", _ctx._frameType);
+ return -1;
+ }
+
+ if (_ctx._frameType == IVI4_FRAMETYPE_BIDIR)
+ _ctx._hasBFrames = true;
+
+ _ctx._hasTransp = _ctx._gb->getBit();
+
+ // unknown bit: Mac decoder ignores this bit, XANIM returns error
+ if (_ctx._gb->getBit()) {
+ warning("Sync bit is set!");
+ return -1;
+ }
+
+ _ctx._dataSize = _ctx._gb->getBit() ? _ctx._gb->getBits(24) : 0;
+
+ // null frames don't contain anything else so we just return
+ if (_ctx._frameType >= IVI4_FRAMETYPE_NULL_FIRST) {
+ warning("Null frame encountered!");
+ return 0;
+ }
+
+ // Check key lock status. If enabled - ignore lock word.
+ // Usually we have to prompt the user for the password, but
+ // we don't do that because Indeo 4 videos can be decoded anyway
+ if (_ctx._gb->getBit()) {
+ _ctx._gb->skip(32);
+ warning("Password-protected clip!");
+ }
+
+ pic_size_indx = _ctx._gb->getBits(3);
+ if (pic_size_indx == IVI4_PIC_SIZE_ESC) {
+ picConf._picHeight = _ctx._gb->getBits(16);
+ picConf._picWidth = _ctx._gb->getBits(16);
+ } else {
+ picConf._picHeight = _ivi4_common_pic_sizes[pic_size_indx * 2 + 1];
+ picConf._picWidth = _ivi4_common_pic_sizes[pic_size_indx * 2];
+ }
+
+ // Decode tile dimensions.
+ _ctx._usesTiling = _ctx._gb->getBit();
+ if (_ctx._usesTiling) {
+ picConf._tileHeight = scaleTileSize(picConf._picHeight, _ctx._gb->getBits(4));
+ picConf._tileWidth = scaleTileSize(picConf._picWidth, _ctx._gb->getBits(4));
+ } else {
+ picConf._tileHeight = picConf._picHeight;
+ picConf._tileWidth = picConf._picWidth;
+ }
+
+ // Decode chroma subsampling. We support only 4:4 aka YVU9.
+ if (_ctx._gb->getBits(2)) {
+ warning("Only YVU9 picture format is supported!");
+ return -1;
+ }
+ picConf._chromaHeight = (picConf._picHeight + 3) >> 2;
+ picConf._chromaWidth = (picConf._picWidth + 3) >> 2;
+
+ // decode subdivision of the planes
+ picConf._lumaBands = decodePlaneSubdivision();
+ picConf._chromaBands = 0;
+ if (picConf._lumaBands)
+ picConf._chromaBands = decodePlaneSubdivision();
+ _ctx._isScalable = picConf._lumaBands != 1 || picConf._chromaBands != 1;
+ if (_ctx._isScalable && (picConf._lumaBands != 4 || picConf._chromaBands != 1)) {
+ warning("Scalability: unsupported subdivision! Luma bands: %d, chroma bands: %d",
+ picConf._lumaBands, picConf._chromaBands);
+ return -1;
+ }
+
+ // check if picture layout was changed and reallocate buffers
+ if (picConf.ivi_pic_config_cmp(_ctx._picConf)) {
+ if (IVIPlaneDesc::initPlanes(_ctx._planes, &picConf, 1)) {
+ warning("Couldn't reallocate color planes!");
+ _ctx._picConf._lumaBands = 0;
+ return -2;
+ }
+
+ _ctx._picConf = picConf;
+
+ // set default macroblock/block dimensions
+ for (p = 0; p <= 2; p++) {
+ for (i = 0; i < (!p ? picConf._lumaBands : picConf._chromaBands); i++) {
+ _ctx._planes[p]._bands[i]._mbSize = !p ? (!_ctx._isScalable ? 16 : 8) : 4;
+ _ctx._planes[p]._bands[i]._blkSize = !p ? 8 : 4;
+ }
+ }
+
+ if (IVIPlaneDesc::initTiles(_ctx._planes, _ctx._picConf._tileWidth,
+ _ctx._picConf._tileHeight)) {
+ warning("Couldn't reallocate internal structures!");
+ return -2;
+ }
+ }
+
+ _ctx._frameNum = _ctx._gb->getBit() ? _ctx._gb->getBits(20) : 0;
+
+ // skip decTimeEst field if present
+ if (_ctx._gb->getBit())
+ _ctx._gb->skip(8);
+
+ // decode macroblock and block huffman codebooks
+ if (_ctx._mbVlc.decodeHuffDesc(&_ctx, _ctx._gb->getBit(), IVI_MB_HUFF) ||
+ _ctx._blkVlc.decodeHuffDesc(&_ctx, _ctx._gb->getBit(), IVI_BLK_HUFF))
+ return -1;
+
+ _ctx._rvmapSel = _ctx._gb->getBit() ? _ctx._gb->getBits(3) : 8;
+
+ _ctx._inImf = _ctx._gb->getBit();
+ _ctx._inQ = _ctx._gb->getBit();
+
+ _ctx._picGlobQuant = _ctx._gb->getBits(5);
+
+ // TODO: ignore this parameter if unused
+ _ctx._unknown1 = _ctx._gb->getBit() ? _ctx._gb->getBits(3) : 0;
+
+ _ctx._checksum = _ctx._gb->getBit() ? _ctx._gb->getBits(16) : 0;
+
+ // skip picture header extension if any
+ while (_ctx._gb->getBit()) {
+ _ctx._gb->skip(8);
+ }
+
+ if (_ctx._gb->getBit()) {
+ warning("Bad blocks bits encountered!");
+ }
+
+ _ctx._gb->align();
+
+ return 0;
+}
+
+void Indeo4Decoder::switchBuffers() {
+ int isPrevRef = 0, isRef = 0;
+
+ switch (_ctx._prevFrameType) {
+ case IVI4_FRAMETYPE_INTRA:
+ case IVI4_FRAMETYPE_INTRA1:
+ case IVI4_FRAMETYPE_INTER:
+ isPrevRef = 1;
+ break;
+ }
+
+ switch (_ctx._frameType) {
+ case IVI4_FRAMETYPE_INTRA:
+ case IVI4_FRAMETYPE_INTRA1:
+ case IVI4_FRAMETYPE_INTER:
+ isRef = 1;
+ break;
+
+ default:
+ break;
+ }
+
+ if (isPrevRef && isRef) {
+ SWAP(_ctx._dstBuf, _ctx._refBuf);
+ } else if (isPrevRef) {
+ SWAP(_ctx._refBuf, _ctx._bRefBuf);
+ SWAP(_ctx._dstBuf, _ctx._refBuf);
+ }
+}
+
+bool Indeo4Decoder::isNonNullFrame() const {
+ return _ctx._frameType < IVI4_FRAMETYPE_NULL_FIRST;
+}
+
+int Indeo4Decoder::decodeBandHeader(IVIBandDesc *band) {
+ int plane, bandNum, indx, transformId, scanIndx;
+ int i;
+ int quantMat;
+
+ plane = _ctx._gb->getBits(2);
+ bandNum = _ctx._gb->getBits(4);
+ if (band->_plane != plane || band->_bandNum != bandNum) {
+ warning("Invalid band header sequence!");
+ return -1;
+ }
+
+ band->_isEmpty = _ctx._gb->getBit();
+ if (!band->_isEmpty) {
+ int old_blk_size = band->_blkSize;
+ // skip header size
+ // If header size is not given, header size is 4 bytes.
+ if (_ctx._gb->getBit())
+ _ctx._gb->skip(16);
+
+ band->_isHalfpel = _ctx._gb->getBits(2);
+ if (band->_isHalfpel >= 2) {
+ warning("Invalid/unsupported mv resolution: %d!",
+ band->_isHalfpel);
+ return -1;
+ }
+ if (!band->_isHalfpel)
+ _ctx._usesFullpel = true;
+
+ band->_checksumPresent = _ctx._gb->getBit();
+ if (band->_checksumPresent)
+ band->_checksum = _ctx._gb->getBits(16);
+
+ indx = _ctx._gb->getBits(2);
+ if (indx == 3) {
+ warning("Invalid block size!");
+ return -1;
+ }
+ band->_mbSize = 16 >> indx;
+ band->_blkSize = 8 >> (indx >> 1);
+
+ band->_inheritMv = _ctx._gb->getBit();
+ band->_inheritQDelta = _ctx._gb->getBit();
+
+ band->_globQuant = _ctx._gb->getBits(5);
+
+ if (!_ctx._gb->getBit() || _ctx._frameType == IVI4_FRAMETYPE_INTRA) {
+ transformId = _ctx._gb->getBits(5);
+ if ((uint)transformId >= FF_ARRAY_ELEMS(_transforms) ||
+ !_transforms[transformId]._invTrans) {
+ warning("Transform %d", transformId);
+ return -3;
+ }
+ if ((transformId >= 7 && transformId <= 9) ||
+ transformId == 17) {
+ warning("DCT transform");
+ return -3;
+ }
+
+ if (transformId < 10 && band->_blkSize < 8) {
+ warning("wrong transform size!");
+ return -1;
+ }
+ if ((transformId >= 0 && transformId <= 2) || transformId == 10)
+ _ctx._usesHaar = true;
+
+ band->_invTransform = _transforms[transformId]._invTrans;
+ band->_dcTransform = _transforms[transformId]._dcTrans;
+ band->_is2dTrans = _transforms[transformId]._is2dTrans;
+
+ if (transformId < 10)
+ band->_transformSize = 8;
+ else
+ band->_transformSize = 4;
+
+ if (band->_blkSize != band->_transformSize) {
+ warning("transform and block size mismatch (%d != %d)", band->_transformSize, band->_blkSize);
+ return -1;
+ }
+
+ scanIndx = _ctx._gb->getBits(4);
+ if (scanIndx == 15) {
+ warning("Custom scan pattern encountered!");
+ return -1;
+ }
+ if (scanIndx > 4 && scanIndx < 10) {
+ if (band->_blkSize != 4) {
+ warning("mismatching scan table!");
+ return -1;
+ }
+ } else if (band->_blkSize != 8) {
+ warning("mismatching scan table!");
+ return -1;
+ }
+
+ band->_scan = _scan_index_to_tab[scanIndx];
+ band->_scanSize = band->_blkSize;
+
+ quantMat = _ctx._gb->getBits(5);
+ if (quantMat == 31) {
+ warning("Custom quant matrix encountered!");
+ return -1;
+ }
+ if ((uint)quantMat >= FF_ARRAY_ELEMS(_quant_index_to_tab)) {
+ warning("Quantization matrix %d", quantMat);
+ return -1;
+ }
+ band->_quantMat = quantMat;
+ } else {
+ if (old_blk_size != band->_blkSize) {
+ warning("The band block size does not match the configuration inherited");
+ return -1;
+ }
+ }
+ if (_quant_index_to_tab[band->_quantMat] > 4 && band->_blkSize == 4) {
+ warning("Invalid quant matrix for 4x4 block encountered!");
+ band->_quantMat = 0;
+ return -1;
+ }
+ if (band->_scanSize != band->_blkSize) {
+ warning("mismatching scan table!");
+ return -1;
+ }
+ if (band->_transformSize == 8 && band->_blkSize < 8) {
+ warning("mismatching _transformSize!");
+ return -1;
+ }
+
+ // decode block huffman codebook
+ if (!_ctx._gb->getBit())
+ band->_blkVlc._tab = _ctx._blkVlc._tab;
+ else
+ if (band->_blkVlc.decodeHuffDesc(&_ctx, 1, IVI_BLK_HUFF))
+ return -1;
+
+ // select appropriate rvmap table for this band
+ band->_rvmapSel = _ctx._gb->getBit() ? _ctx._gb->getBits(3) : 8;
+
+ // decode rvmap probability corrections if any
+ band->_numCorr = 0; // there is no corrections
+ if (_ctx._gb->getBit()) {
+ band->_numCorr = _ctx._gb->getBits(8); // get number of correction pairs
+ if (band->_numCorr > 61) {
+ warning("Too many corrections: %d",
+ band->_numCorr);
+ return -1;
+ }
+
+ // read correction pairs
+ for (i = 0; i < band->_numCorr * 2; i++)
+ band->_corr[i] = _ctx._gb->getBits(8);
+ }
+ }
+
+ if (band->_blkSize == 8) {
+ band->_intraBase = &_ivi4_quant_8x8_intra[_quant_index_to_tab[band->_quantMat]][0];
+ band->_interBase = &_ivi4_quant_8x8_inter[_quant_index_to_tab[band->_quantMat]][0];
+ } else {
+ band->_intraBase = &_ivi4_quant_4x4_intra[_quant_index_to_tab[band->_quantMat]][0];
+ band->_interBase = &_ivi4_quant_4x4_inter[_quant_index_to_tab[band->_quantMat]][0];
+ }
+
+ // Indeo 4 doesn't use scale tables
+ band->_intraScale = NULL;
+ band->_interScale = NULL;
+
+ _ctx._gb->align();
+
+ if (!band->_scan) {
+ warning("band->_scan not set");
+ return -1;
+ }
+
+ return 0;
+}
+
+int Indeo4Decoder::decodeMbInfo(IVIBandDesc *band, IVITile *tile) {
+ int x, y, mvX, mvY, mvDelta, offs, mbOffset, blksPerMb,
+ mvScale, mbTypeBits, s;
+ IVIMbInfo *mb, *refMb;
+ int row_offset = band->_mbSize * band->_pitch;
+
+ mb = tile->_mbs;
+ refMb = tile->_refMbs;
+ offs = tile->_yPos * band->_pitch + tile->_xPos;
+
+ blksPerMb = band->_mbSize != band->_blkSize ? 4 : 1;
+ mbTypeBits = _ctx._frameType == IVI4_FRAMETYPE_BIDIR ? 2 : 1;
+
+ // scale factor for motion vectors
+ mvScale = (_ctx._planes[0]._bands[0]._mbSize >> 3) - (band->_mbSize >> 3);
+ mvX = mvY = 0;
+
+ if (((tile->_width + band->_mbSize - 1) / band->_mbSize) * ((tile->_height + band->_mbSize - 1) / band->_mbSize) != tile->_numMBs) {
+ warning("numMBs mismatch %d %d %d %d", tile->_width, tile->_height, band->_mbSize, tile->_numMBs);
+ return -1;
+ }
+
+ for (y = tile->_yPos; y < tile->_yPos + tile->_height; y += band->_mbSize) {
+ mbOffset = offs;
+
+ for (x = tile->_xPos; x < tile->_xPos + tile->_width; x += band->_mbSize) {
+ mb->_xPos = x;
+ mb->_yPos = y;
+ mb->_bufOffs = mbOffset;
+ mb->_bMvX = mb->_bMvY = 0;
+
+ if (_ctx._gb->getBit()) {
+ if (_ctx._frameType == IVI4_FRAMETYPE_INTRA) {
+ warning("Empty macroblock in an INTRA picture!");
+ return -1;
+ }
+ mb->_type = 1; // empty macroblocks are always INTER
+ mb->_cbp = 0; // all blocks are empty
+
+ mb->_qDelta = 0;
+ if (!band->_plane && !band->_bandNum && _ctx._inQ) {
+ mb->_qDelta = _ctx._gb->getVLC2(_ctx._mbVlc._tab->_table,
+ IVI_VLC_BITS, 1);
+ mb->_qDelta = IVI_TOSIGNED(mb->_qDelta);
+ }
+
+ mb->_mvX = mb->_mvY = 0; // no motion vector coded
+ if (band->_inheritMv && refMb) {
+ // motion vector inheritance
+ if (mvScale) {
+ mb->_mvX = scaleMV(refMb->_mvX, mvScale);
+ mb->_mvY = scaleMV(refMb->_mvY, mvScale);
+ } else {
+ mb->_mvX = refMb->_mvX;
+ mb->_mvY = refMb->_mvY;
+ }
+ }
+ } else {
+ if (band->_inheritMv) {
+ // copy mb_type from corresponding reference mb
+ if (!refMb) {
+ warning("refMb unavailable");
+ return -1;
+ }
+ mb->_type = refMb->_type;
+ } else if (_ctx._frameType == IVI4_FRAMETYPE_INTRA ||
+ _ctx._frameType == IVI4_FRAMETYPE_INTRA1) {
+ mb->_type = 0; // mb_type is always INTRA for intra-frames
+ } else {
+ mb->_type = _ctx._gb->getBits(mbTypeBits);
+ }
+
+ mb->_cbp = _ctx._gb->getBits(blksPerMb);
+
+ mb->_qDelta = 0;
+ if (band->_inheritQDelta) {
+ if (refMb) mb->_qDelta = refMb->_qDelta;
+ } else if (mb->_cbp || (!band->_plane && !band->_bandNum &&
+ _ctx._inQ)) {
+ mb->_qDelta = _ctx._gb->getVLC2(_ctx._mbVlc._tab->_table,
+ IVI_VLC_BITS, 1);
+ mb->_qDelta = IVI_TOSIGNED(mb->_qDelta);
+ }
+
+ if (!mb->_type) {
+ mb->_mvX = mb->_mvY = 0; // there is no motion vector in intra-macroblocks
+ } else {
+ if (band->_inheritMv) {
+ if (refMb) {
+ // motion vector inheritance
+ if (mvScale) {
+ mb->_mvX = scaleMV(refMb->_mvX, mvScale);
+ mb->_mvY = scaleMV(refMb->_mvY, mvScale);
+ } else {
+ mb->_mvX = refMb->_mvX;
+ mb->_mvY = refMb->_mvY;
+ }
+ }
+ } else {
+ // decode motion vector deltas
+ mvDelta = _ctx._gb->getVLC2(_ctx._mbVlc._tab->_table,
+ IVI_VLC_BITS, 1);
+ mvY += IVI_TOSIGNED(mvDelta);
+ mvDelta = _ctx._gb->getVLC2(_ctx._mbVlc._tab->_table,
+ IVI_VLC_BITS, 1);
+ mvX += IVI_TOSIGNED(mvDelta);
+ mb->_mvX = mvX;
+ mb->_mvY = mvY;
+ if (mb->_type == 3) {
+ mvDelta = _ctx._gb->getVLC2(
+ _ctx._mbVlc._tab->_table,
+ IVI_VLC_BITS, 1);
+ mvY += IVI_TOSIGNED(mvDelta);
+ mvDelta = _ctx._gb->getVLC2(
+ _ctx._mbVlc._tab->_table,
+ IVI_VLC_BITS, 1);
+ mvX += IVI_TOSIGNED(mvDelta);
+ mb->_bMvX = -mvX;
+ mb->_bMvY = -mvY;
+ }
+ }
+ if (mb->_type == 2) {
+ mb->_bMvX = -mb->_mvX;
+ mb->_bMvY = -mb->_mvY;
+ mb->_mvX = 0;
+ mb->_mvY = 0;
+ }
+ }
+ }
+
+ s = band->_isHalfpel;
+ if (mb->_type)
+ if (x + (mb->_mvX >> s) + (y + (mb->_mvY >> s))*band->_pitch < 0 ||
+ x + ((mb->_mvX + s) >> s) + band->_mbSize - 1
+ + (y + band->_mbSize - 1 + ((mb->_mvY + s) >> s))*band->_pitch > band->_bufSize - 1) {
+ warning("motion vector %d %d outside reference", x*s + mb->_mvX, y*s + mb->_mvY);
+ return -1;
+ }
+
+ mb++;
+ if (refMb)
+ refMb++;
+ mbOffset += band->_mbSize;
+ }
+
+ offs += row_offset;
+ }
+
+ _ctx._gb->align();
+ return 0;
+}
+
+int Indeo4Decoder::scaleTileSize(int defSize, int sizeFactor) {
+ return sizeFactor == 15 ? defSize : (sizeFactor + 1) << 5;
+}
+
+int Indeo4Decoder::decodePlaneSubdivision() {
+ int i;
+
+ switch (_ctx._gb->getBits(2)) {
+ case 3:
+ return 1;
+
+ case 2:
+ for (i = 0; i < 4; i++)
+ if (_ctx._gb->getBits(2) != 3)
+ return 0;
+ return 4;
+
+ default:
+ return 0;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+/**
+ * Indeo 4 8x8 scan (zigzag) patterns
+ */
+static const uint8 ivi4AlternateScan8x8[64] = {
+ 0, 8, 1, 9, 16, 24, 2, 3, 17, 25, 10, 11, 32, 40, 48, 56,
+ 4, 5, 6, 7, 33, 41, 49, 57, 18, 19, 26, 27, 12, 13, 14, 15,
+ 34, 35, 43, 42, 50, 51, 59, 58, 20, 21, 22, 23, 31, 30, 29, 28,
+ 36, 37, 38, 39, 47, 46, 45, 44, 52, 53, 54, 55, 63, 62, 61, 60
+};
+
+static const uint8 ivi4AlternateScan4x4[16] = {
+ 0, 1, 4, 5, 8, 12, 2, 3, 9, 13, 6, 7, 10, 11, 14, 15
+};
+
+static const uint8 ivi4VerticalScan4x4[16] = {
+ 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15
+};
+
+static const uint8 ivi4HorizontalScan4x4[16] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+};
+
+const uint Indeo4Decoder::_ivi4_common_pic_sizes[14] = {
+ 640, 480, 320, 240, 160, 120, 704, 480, 352, 240, 352, 288, 176, 144
+};
+
+Indeo4Decoder::Transform Indeo4Decoder::_transforms[18] = {
+ { IndeoDSP::ffIviInverseHaar8x8, IndeoDSP::ffIviDcHaar2d, 1 },
+ { IndeoDSP::ffIviRowHaar8, IndeoDSP::ffIviDcHaar2d, 0 },
+ { IndeoDSP::ffIviColHaar8, IndeoDSP::ffIviDcHaar2d, 0 },
+ { IndeoDSP::ffIviPutPixels8x8, IndeoDSP::ffIviPutDcPixel8x8, 1 },
+ { IndeoDSP::ffIviInverseSlant8x8, IndeoDSP::ffIviDcSlant2d, 1 },
+ { IndeoDSP::ffIviRowSlant8, IndeoDSP::ffIviDcRowSlant, 1 },
+ { IndeoDSP::ffIviColSlant8, IndeoDSP::ffIviDcColSlant, 1 },
+ { NULL, NULL, 0 }, // inverse DCT 8x8
+ { NULL, NULL, 0 }, // inverse DCT 8x1
+ { NULL, NULL, 0 }, // inverse DCT 1x8
+ { IndeoDSP::ffIviInverseHaar4x4, IndeoDSP::ffIviDcHaar2d, 1 },
+ { IndeoDSP::ffIviInverseSlant4x4, IndeoDSP::ffIviDcSlant2d, 1 },
+ { NULL, NULL, 0 }, // no transform 4x4
+ { IndeoDSP::ffIviRowHaar4, IndeoDSP::ffIviDcHaar2d, 0 },
+ { IndeoDSP::ffIviColHaar4, IndeoDSP::ffIviDcHaar2d, 0 },
+ { IndeoDSP::ffIviRowSlant4, IndeoDSP::ffIviDcRowSlant, 0 },
+ { IndeoDSP::ffIviColSlant4, IndeoDSP::ffIviDcColSlant, 0 },
+ { NULL, NULL, 0 }, // inverse DCT 4x4
+};
+
+const uint8 *const Indeo4Decoder::_scan_index_to_tab[15] = {
+ // for 8x8 transforms
+ ffZigZagDirect,
+ ivi4AlternateScan8x8,
+ _ffIviHorizontalScan8x8,
+ _ffIviVerticalScan8x8,
+ ffZigZagDirect,
+
+ // for 4x4 transforms
+ _ffIviDirectScan4x4,
+ ivi4AlternateScan4x4,
+ ivi4VerticalScan4x4,
+ ivi4HorizontalScan4x4,
+ _ffIviDirectScan4x4,
+
+ // TODO: check if those are needed
+ _ffIviHorizontalScan8x8,
+ _ffIviHorizontalScan8x8,
+ _ffIviHorizontalScan8x8,
+ _ffIviHorizontalScan8x8,
+ _ffIviHorizontalScan8x8
+};
+
+/**
+ * Indeo 4 dequant tables
+ */
+const uint16 Indeo4Decoder::_ivi4_quant_8x8_intra[9][64] = {
+ {
+ 43, 342, 385, 470, 555, 555, 598, 726,
+ 342, 342, 470, 513, 555, 598, 726, 769,
+ 385, 470, 555, 555, 598, 726, 726, 811,
+ 470, 470, 555, 555, 598, 726, 769, 854,
+ 470, 555, 555, 598, 683, 726, 854, 1025,
+ 555, 555, 598, 683, 726, 854, 1025, 1153,
+ 555, 555, 598, 726, 811, 982, 1195, 1451,
+ 555, 598, 726, 811, 982, 1195, 1451, 1793
+ },
+ {
+ 86, 1195, 2390, 2390, 4865, 4865, 4865, 4865,
+ 1195, 1195, 2390, 2390, 4865, 4865, 4865, 4865,
+ 2390, 2390, 4865, 4865, 6827, 6827, 6827, 6827,
+ 2390, 2390, 4865, 4865, 6827, 6827, 6827, 6827,
+ 4865, 4865, 6827, 6827, 6827, 6827, 6827, 6827,
+ 4865, 4865, 6827, 6827, 6827, 6827, 6827, 6827,
+ 4865, 4865, 6827, 6827, 6827, 6827, 6827, 6827,
+ 4865, 4865, 6827, 6827, 6827, 6827, 6827, 6827
+ },
+ {
+ 235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+ 235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+ 235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+ 235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+ 235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+ 235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+ 235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+ 235, 1067, 1195, 1323, 1451, 1579, 1707, 1835
+ },
+ {
+ 1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+ 1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+ 1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+ 1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+ 1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+ 1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+ 1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+ 1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414
+ },
+ {
+ 897, 897, 897, 897, 897, 897, 897, 897,
+ 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067,
+ 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238,
+ 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409,
+ 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579,
+ 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
+ 1921, 1921, 1921, 1921, 1921, 1921, 1921, 1921,
+ 2091, 2091, 2091, 2091, 2091, 2091, 2091, 2091
+ },
+ {
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+ 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+ 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+ 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+ 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+ 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414
+ },
+ {
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390
+ },
+ {
+ 22, 171, 214, 257, 257, 299, 299, 342,
+ 171, 171, 257, 257, 299, 299, 342, 385,
+ 214, 257, 257, 299, 299, 342, 342, 385,
+ 257, 257, 257, 299, 299, 342, 385, 427,
+ 257, 257, 299, 299, 342, 385, 427, 513,
+ 257, 299, 299, 342, 385, 427, 513, 598,
+ 299, 299, 299, 385, 385, 470, 598, 726,
+ 299, 299, 385, 385, 470, 598, 726, 897
+ },
+ {
+ 86, 598, 1195, 1195, 2390, 2390, 2390, 2390,
+ 598, 598, 1195, 1195, 2390, 2390, 2390, 2390,
+ 1195, 1195, 2390, 2390, 3414, 3414, 3414, 3414,
+ 1195, 1195, 2390, 2390, 3414, 3414, 3414, 3414,
+ 2390, 2390, 3414, 3414, 3414, 3414, 3414, 3414,
+ 2390, 2390, 3414, 3414, 3414, 3414, 3414, 3414,
+ 2390, 2390, 3414, 3414, 3414, 3414, 3414, 3414,
+ 2390, 2390, 3414, 3414, 3414, 3414, 3414, 3414
+ }
+};
+
+const uint16 Indeo4Decoder::_ivi4_quant_8x8_inter[9][64] = {
+ {
+ 427, 427, 470, 427, 427, 427, 470, 470,
+ 427, 427, 470, 427, 427, 427, 470, 470,
+ 470, 470, 470, 470, 470, 470, 470, 470,
+ 427, 427, 470, 470, 427, 427, 470, 470,
+ 427, 427, 470, 427, 427, 427, 470, 470,
+ 427, 427, 470, 427, 427, 427, 470, 470,
+ 470, 470, 470, 470, 470, 470, 470, 470,
+ 470, 470, 470, 470, 470, 470, 470, 470
+ },
+ {
+ 1707, 1707, 2433, 2433, 3414, 3414, 3414, 3414,
+ 1707, 1707, 2433, 2433, 3414, 3414, 3414, 3414,
+ 2433, 2433, 3414, 3414, 4822, 4822, 4822, 4822,
+ 2433, 2433, 3414, 3414, 4822, 4822, 4822, 4822,
+ 3414, 3414, 4822, 4822, 3414, 3414, 3414, 3414,
+ 3414, 3414, 4822, 4822, 3414, 3414, 3414, 3414,
+ 3414, 3414, 4822, 4822, 3414, 3414, 3414, 3414,
+ 3414, 3414, 4822, 4822, 3414, 3414, 3414, 3414
+ },
+ {
+ 1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+ 1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+ 1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+ 1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+ 1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+ 1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+ 1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+ 1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281
+ },
+ {
+ 2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+ 2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+ 2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+ 2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+ 2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+ 2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+ 2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+ 2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433
+ },
+ {
+ 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195,
+ 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195,
+ 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281,
+ 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238,
+ 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195,
+ 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195,
+ 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281,
+ 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281
+ },
+ {
+ 2433, 2433, 2433, 2433, 2433, 2433, 2433, 2433,
+ 2433, 2433, 2433, 2433, 2433, 2433, 2433, 2433,
+ 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+ 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+ 2433, 2433, 2433, 2433, 2433, 2433, 2433, 2433,
+ 2433, 2433, 2433, 2433, 2433, 2433, 2433, 2433,
+ 2433, 2433, 2433, 2433, 2433, 2433, 2433, 2433,
+ 2433, 2433, 2433, 2433, 2433, 2433, 2433, 2433
+ },
+ {
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707
+ },
+ {
+ 86, 171, 171, 214, 214, 214, 214, 257,
+ 171, 171, 214, 214, 214, 214, 257, 257,
+ 171, 214, 214, 214, 214, 257, 257, 257,
+ 214, 214, 214, 214, 257, 257, 257, 299,
+ 214, 214, 214, 257, 257, 257, 299, 299,
+ 214, 214, 257, 257, 257, 299, 299, 299,
+ 214, 257, 257, 257, 299, 299, 299, 342,
+ 257, 257, 257, 299, 299, 299, 342, 342
+ },
+ {
+ 854, 854, 1195, 1195, 1707, 1707, 1707, 1707,
+ 854, 854, 1195, 1195, 1707, 1707, 1707, 1707,
+ 1195, 1195, 1707, 1707, 2390, 2390, 2390, 2390,
+ 1195, 1195, 1707, 1707, 2390, 2390, 2390, 2390,
+ 1707, 1707, 2390, 2390, 1707, 1707, 1707, 1707,
+ 1707, 1707, 2390, 2390, 1707, 1707, 1707, 1707,
+ 1707, 1707, 2390, 2390, 1707, 1707, 1707, 1707,
+ 1707, 1707, 2390, 2390, 1707, 1707, 1707, 1707
+ }
+};
+
+const uint16 Indeo4Decoder::_ivi4_quant_4x4_intra[5][16] = {
+ {
+ 22, 214, 257, 299,
+ 214, 257, 299, 342,
+ 257, 299, 342, 427,
+ 299, 342, 427, 513
+ },
+ {
+ 129, 1025, 1451, 1451,
+ 1025, 1025, 1451, 1451,
+ 1451, 1451, 2049, 2049,
+ 1451, 1451, 2049, 2049
+ },
+ {
+ 43, 171, 171, 171,
+ 43, 171, 171, 171,
+ 43, 171, 171, 171,
+ 43, 171, 171, 171
+ },
+ {
+ 43, 43, 43, 43,
+ 171, 171, 171, 171,
+ 171, 171, 171, 171,
+ 171, 171, 171, 171
+ },
+ {
+ 43, 43, 43, 43,
+ 43, 43, 43, 43,
+ 43, 43, 43, 43,
+ 43, 43, 43, 43
+ }
+};
+
+const uint16 Indeo4Decoder::_ivi4_quant_4x4_inter[5][16] = {
+ {
+ 107, 214, 257, 299,
+ 214, 257, 299, 299,
+ 257, 299, 299, 342,
+ 299, 299, 342, 342
+ },
+ {
+ 513, 1025, 1238, 1238,
+ 1025, 1025, 1238, 1238,
+ 1238, 1238, 1451, 1451,
+ 1238, 1238, 1451, 1451
+ },
+ {
+ 43, 171, 171, 171,
+ 43, 171, 171, 171,
+ 43, 171, 171, 171,
+ 43, 171, 171, 171
+ },
+ {
+ 43, 43, 43, 43,
+ 171, 171, 171, 171,
+ 171, 171, 171, 171,
+ 171, 171, 171, 171
+ },
+ {
+ 43, 43, 43, 43,
+ 43, 43, 43, 43,
+ 43, 43, 43, 43,
+ 43, 43, 43, 43
+ }
+};
+
+const uint8 Indeo4Decoder::_quant_index_to_tab[22] = {
+ 0, 1, 0, 2, 1, 3, 0, 4, 1, 5, 0, 1, 6, 7, 8, // for 8x8 quant matrixes
+ 0, 1, 2, 2, 3, 3, 4 // for 4x4 quant matrixes
+};
+
+} // End of namespace Image
diff --git a/image/codecs/indeo4.h b/image/codecs/indeo4.h
new file mode 100644
index 0000000000..4a6279db37
--- /dev/null
+++ b/image/codecs/indeo4.h
@@ -0,0 +1,140 @@
+/* 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.
+ *
+ */
+
+/* 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/indeo/get_bits.h"
+#include "image/codecs/indeo/indeo.h"
+
+namespace Image {
+
+using namespace Indeo;
+
+/**
+ * Intel Indeo 4 decoder.
+ *
+ * Used by AVI.
+ *
+ * Used in video:
+ * - AVIDecoder
+ */
+class Indeo4Decoder : public IndeoDecoderBase {
+ struct Transform {
+ InvTransformPtr *_invTrans;
+ DCTransformPtr *_dcTrans;
+ bool _is2dTrans;
+ };
+public:
+ Indeo4Decoder(uint16 width, uint16 height);
+ virtual ~Indeo4Decoder() {}
+
+ virtual const Graphics::Surface *decodeFrame(Common::SeekableReadStream &stream);
+
+ static bool isIndeo4(Common::SeekableReadStream &stream);
+protected:
+ /**
+ * Decode the Indeo 4 picture header.
+ * @returns 0 = Ok, negative number = error
+ */
+ virtual int decodePictureHeader();
+
+ /**
+ * Rearrange decoding and reference buffers.
+ */
+ virtual void switchBuffers();
+
+ virtual bool isNonNullFrame() const;
+
+ /**
+ * Decode Indeo 4 band header.
+ *
+ * @param[in,out] band pointer to the band descriptor
+ * @returns result code: 0 = OK, negative number = error
+ */
+ virtual int decodeBandHeader(IVIBandDesc *band);
+
+ /**
+ * 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);
+private:
+ int scaleTileSize(int defSize, int sizeFactor);
+
+ /**
+ * Decode subdivision of a plane.
+ * This is a simplified version that checks for two supported subdivisions:
+ * - 1 wavelet band per plane, size factor 1:1, code pattern: 3
+ * - 4 wavelet bands per plane, size factor 1:4, code pattern: 2,3,3,3,3
+ * Anything else is either unsupported or corrupt.
+ *
+ * @param[in,out] gb The GetBit context
+ * @returns Number of wavelet bands or 0 on error
+ */
+ int decodePlaneSubdivision();
+
+private:
+ /**
+ * Standard picture dimensions
+ */
+ static const uint _ivi4_common_pic_sizes[14];
+
+ /**
+ * Transformations list
+ */
+ static Transform _transforms[18];
+
+ static const uint8 *const _scan_index_to_tab[15];
+
+ /**
+ * Indeo 4 dequant tables
+ */
+ static const uint16 _ivi4_quant_8x8_intra[9][64];
+
+ static const uint16 _ivi4_quant_8x8_inter[9][64];
+
+ static const uint16 _ivi4_quant_4x4_intra[5][16];
+
+ static const uint16 _ivi4_quant_4x4_inter[5][16];
+
+ /**
+ * Table for mapping quant matrix index from the bitstream
+ * into internal quant table number.
+ */
+ static const uint8 _quant_index_to_tab[22];
+};
+
+} // End of namespace Image
+
+#endif
diff --git a/image/codecs/indeo5.cpp b/image/codecs/indeo5.cpp
new file mode 100644
index 0000000000..d5ce571bea
--- /dev/null
+++ b/image/codecs/indeo5.cpp
@@ -0,0 +1,744 @@
+/* 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.
+ *
+ */
+
+/* Intel Indeo 5 decompressor, derived from ffmpeg.
+ *
+ * Original copyright note: * Intel Indeo 3 (IV41, IV42, etc.) video decoder for ffmpeg
+ * written, produced, and directed by Alan Smithee
+ */
+
+#include "common/memstream.h"
+#include "common/textconsole.h"
+#include "graphics/yuv_to_rgb.h"
+#include "image/codecs/indeo5.h"
+#include "image/codecs/indeo/indeo_dsp.h"
+#include "image/codecs/indeo/mem.h"
+
+namespace Image {
+
+/**
+ * Indeo5 frame types.
+ */
+enum {
+ FRAMETYPE_INTRA = 0,
+ FRAMETYPE_INTER = 1, ///< non-droppable P-frame
+ FRAMETYPE_INTER_SCAL = 2, ///< droppable P-frame used in the scalability mode
+ FRAMETYPE_INTER_NOREF = 3, ///< droppable P-frame
+ FRAMETYPE_NULL = 4 ///< empty frame with no data
+};
+
+#define IVI5_PIC_SIZE_ESC 15
+
+Indeo5Decoder::Indeo5Decoder(uint16 width, uint16 height) : IndeoDecoderBase(width, height) {
+ _ctx._isIndeo4 = false;
+ _ctx._refBuf = 1;
+ _ctx._bRefBuf = 3;
+ _ctx._pFrame = new AVFrame();
+}
+
+bool Indeo5Decoder::isIndeo5(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 5-bit word has the correct identifier
+ Indeo::GetBits gb(new Common::MemoryReadStream(buffer, 16 * 8));
+ bool isIndeo5 = gb.getBits(5) == 0x1F;
+
+ return isIndeo5;
+}
+
+const Graphics::Surface *Indeo5Decoder::decodeFrame(Common::SeekableReadStream &stream) {
+ // Not Indeo 5? Fail
+ if (!isIndeo5(stream))
+ return nullptr;
+
+ // Set up the frame data buffer
+ byte *frameData = new byte[stream.size()];
+ stream.read(frameData, stream.size());
+ _ctx._frameData = frameData;
+ _ctx._frameSize = stream.size();
+
+ // Set up the GetBits instance for reading the data
+ _ctx._gb = new GetBits(new Common::MemoryReadStream(_ctx._frameData, _ctx._frameSize * 8));
+
+ // Decode the frame
+ int err = decodeIndeoFrame();
+
+ // Free the bit reader and frame buffer
+ delete _ctx._gb;
+ _ctx._gb = nullptr;
+ delete[] frameData;
+ _ctx._frameData = nullptr;
+ _ctx._frameSize = 0;
+
+ return (err < 0) ? nullptr : &_surface->rawSurface();
+}
+
+int Indeo5Decoder::decodePictureHeader() {
+ IVIPicConfig picConf;
+ int ret;
+
+ if (_ctx._gb->getBits(5) != 0x1F) {
+ warning("Invalid picture start code!");
+ return -1;
+ }
+
+ _ctx._prevFrameType = _ctx._frameType;
+ _ctx._frameType = _ctx._gb->getBits(3);
+ if (_ctx._frameType >= 5) {
+ warning("Invalid frame type: %d", _ctx._frameType);
+ return -1;
+ }
+
+ _ctx._frameNum = _ctx._gb->getBits(8);
+
+ if (_ctx._frameType == FRAMETYPE_INTRA) {
+ if ((ret = decode_gop_header()) < 0) {
+ warning("Invalid GOP header, skipping frames.");
+ _ctx._gopInvalid = true;
+ return ret;
+ }
+ _ctx._gopInvalid = false;
+ }
+
+ if (_ctx._frameType == FRAMETYPE_INTER_SCAL && !_ctx._isScalable) {
+ warning("Scalable inter frame in non scalable stream");
+ _ctx._frameType = FRAMETYPE_INTER;
+ return -1;
+ }
+
+ if (_ctx._frameType != FRAMETYPE_NULL) {
+ _ctx._frameFlags = _ctx._gb->getBits(8);
+
+ _ctx._picHdrSize = (_ctx._frameFlags & 1) ? _ctx._gb->getBits(24) : 0;
+
+ _ctx._checksum = (_ctx._frameFlags & 0x10) ? _ctx._gb->getBits(16) : 0;
+
+ // skip unknown extension if any
+ if (_ctx._frameFlags & 0x20)
+ skip_hdr_extension(); // XXX: untested
+
+ // decode macroblock huffman codebook
+ ret = _ctx._mbVlc.decodeHuffDesc(&_ctx, _ctx._frameFlags & 0x40,
+ IVI_MB_HUFF);
+ if (ret < 0)
+ return ret;
+
+ _ctx._gb->skip(3); // FIXME: unknown meaning!
+ }
+
+ _ctx._gb->align();
+ return 0;
+}
+
+void Indeo5Decoder::switchBuffers() {
+ switch (_ctx._prevFrameType) {
+ case FRAMETYPE_INTRA:
+ case FRAMETYPE_INTER:
+ _ctx._bufSwitch ^= 1;
+ _ctx._dstBuf = _ctx._bufSwitch;
+ _ctx._refBuf = _ctx._bufSwitch ^ 1;
+ break;
+
+ case FRAMETYPE_INTER_SCAL:
+ if (!_ctx._interScal) {
+ _ctx._ref2Buf = 2;
+ _ctx._interScal = 1;
+ }
+ SWAP(_ctx._dstBuf, _ctx._ref2Buf);
+ _ctx._refBuf = _ctx._ref2Buf;
+ break;
+
+ case FRAMETYPE_INTER_NOREF:
+ break;
+ }
+
+ switch (_ctx._frameType) {
+ case FRAMETYPE_INTRA:
+ _ctx._bufSwitch = 0;
+ // FALLTHROUGH
+ case FRAMETYPE_INTER:
+ _ctx._interScal = 0;
+ _ctx._dstBuf = _ctx._bufSwitch;
+ _ctx._refBuf = _ctx._bufSwitch ^ 1;
+ break;
+
+ case FRAMETYPE_INTER_SCAL:
+ case FRAMETYPE_INTER_NOREF:
+ case FRAMETYPE_NULL:
+ break;
+ }
+}
+
+bool Indeo5Decoder::isNonNullFrame() const {
+ return _ctx._frameType != FRAMETYPE_NULL;
+}
+
+int Indeo5Decoder::decodeBandHeader(IVIBandDesc *band) {
+ int i, ret;
+ uint8 bandFlags;
+
+ bandFlags = _ctx._gb->getBits(8);
+
+ if (bandFlags & 1) {
+ band->_isEmpty = true;
+ return 0;
+ }
+
+ band->_dataSize = (_ctx._frameFlags & 0x80) ? _ctx._gb->getBits(24) : 0;
+
+ band->_inheritMv = (bandFlags & 2) != 0;
+ band->_inheritQDelta = (bandFlags & 8) != 0;
+ band->_qdeltaPresent = (bandFlags & 4) != 0;
+ if (!band->_qdeltaPresent)
+ band->_inheritQDelta = 1;
+
+ // decode rvmap probability corrections if any
+ band->_numCorr = 0; // there are no corrections
+ if (bandFlags & 0x10) {
+ band->_numCorr = _ctx._gb->getBits(8); // get number of correction pairs
+ if (band->_numCorr > 61) {
+ warning("Too many corrections: %d", band->_numCorr);
+ return -1;
+ }
+
+ // read correction pairs
+ for (i = 0; i < band->_numCorr * 2; i++)
+ band->_corr[i] = _ctx._gb->getBits(8);
+ }
+
+ // select appropriate rvmap table for this band
+ band->_rvmapSel = (bandFlags & 0x40) ? _ctx._gb->getBits(3) : 8;
+
+ // decode block huffman codebook
+ ret = band->_blkVlc.decodeHuffDesc(&_ctx, bandFlags & 0x80, IVI_BLK_HUFF);
+ if (ret < 0)
+ return ret;
+
+ band->_checksumPresent = _ctx._gb->getBit();
+ if (band->_checksumPresent)
+ band->_checksum = _ctx._gb->getBits(16);
+
+ band->_globQuant = _ctx._gb->getBits(5);
+
+ // skip unknown extension if any
+ if (bandFlags & 0x20) { // XXX: untested
+ _ctx._gb->align();
+ skip_hdr_extension();
+ }
+
+ _ctx._gb->align();
+
+ return 0;
+}
+
+int Indeo5Decoder::decodeMbInfo(IVIBandDesc *band, IVITile *tile) {
+ int x, y, mvX, mvY, mvDelta, offs, mbOffset, mvScale, blksPerMb, s;
+ IVIMbInfo *mb, *refMb;
+ int rowOffset = band->_mbSize * band->_pitch;
+
+ mb = tile->_mbs;
+ refMb = tile->_refMbs;
+ offs = tile->_yPos * band->_pitch + tile->_xPos;
+
+ if (!refMb &&
+ ((band->_qdeltaPresent && band->_inheritQDelta) || band->_inheritMv))
+ return -1;
+
+ if (tile->_numMBs != IVI_MBs_PER_TILE(tile->_width, tile->_height, band->_mbSize)) {
+ warning("Allocated tile size %d mismatches parameters %d",
+ tile->_numMBs, IVI_MBs_PER_TILE(tile->_width, tile->_height, band->_mbSize));
+ return -1;
+ }
+
+ // scale factor for motion vectors
+ mvScale = (_ctx._planes[0]._bands[0]._mbSize >> 3) - (band->_mbSize >> 3);
+ mvX = mvY = 0;
+
+ for (y = tile->_yPos; y < (tile->_yPos + tile->_height); y += band->_mbSize) {
+ mbOffset = offs;
+
+ for (x = tile->_xPos; x < (tile->_xPos + tile->_width); x += band->_mbSize) {
+ mb->_xPos = x;
+ mb->_yPos = y;
+ mb->_bufOffs = mbOffset;
+
+ if (_ctx._gb->getBit()) {
+ if (_ctx._frameType == FRAMETYPE_INTRA) {
+ warning("Empty macroblock in an INTRA picture!");
+ return -1;
+ }
+ mb->_type = 1; // empty macroblocks are always INTER
+ mb->_cbp = 0; // all blocks are empty
+
+ mb->_qDelta = 0;
+ if (!band->_plane && !band->_bandNum && (_ctx._frameFlags & 8)) {
+ mb->_qDelta = _ctx._gb->getVLC2(_ctx._mbVlc._tab->_table, IVI_VLC_BITS, 1);
+ mb->_qDelta = IVI_TOSIGNED(mb->_qDelta);
+ }
+
+ mb->_mvX = mb->_mvY = 0; // no motion vector coded
+ if (band->_inheritMv && refMb) {
+ // motion vector inheritance
+ if (mvScale) {
+ mb->_mvX = scaleMV(refMb->_mvX, mvScale);
+ mb->_mvY = scaleMV(refMb->_mvY, mvScale);
+ } else {
+ mb->_mvX = refMb->_mvX;
+ mb->_mvY = refMb->_mvY;
+ }
+ }
+ } else {
+ if (band->_inheritMv && refMb) {
+ mb->_type = refMb->_type; // copy mb_type from corresponding reference mb
+ } else if (_ctx._frameType == FRAMETYPE_INTRA) {
+ mb->_type = 0; // mb_type is always INTRA for intra-frames
+ } else {
+ mb->_type = _ctx._gb->getBit();
+ }
+
+ blksPerMb = band->_mbSize != band->_blkSize ? 4 : 1;
+ mb->_cbp = _ctx._gb->getBits(blksPerMb);
+
+ mb->_qDelta = 0;
+ if (band->_qdeltaPresent) {
+ if (band->_inheritQDelta) {
+ if (refMb) mb->_qDelta = refMb->_qDelta;
+ } else if (mb->_cbp || (!band->_plane && !band->_bandNum &&
+ (_ctx._frameFlags & 8))) {
+ mb->_qDelta = _ctx._gb->getVLC2(_ctx._mbVlc._tab->_table, IVI_VLC_BITS, 1);
+ mb->_qDelta = IVI_TOSIGNED(mb->_qDelta);
+ }
+ }
+
+ if (!mb->_type) {
+ mb->_mvX = mb->_mvY = 0; // there is no motion vector in intra-macroblocks
+ } else {
+ if (band->_inheritMv && refMb) {
+ // motion vector inheritance
+ if (mvScale) {
+ mb->_mvX = scaleMV(refMb->_mvX, mvScale);
+ mb->_mvY = scaleMV(refMb->_mvY, mvScale);
+ } else {
+ mb->_mvX = refMb->_mvX;
+ mb->_mvY = refMb->_mvY;
+ }
+ } else {
+ // decode motion vector deltas
+ mvDelta = _ctx._gb->getVLC2(_ctx._mbVlc._tab->_table, IVI_VLC_BITS, 1);
+ mvY += IVI_TOSIGNED(mvDelta);
+ mvDelta = _ctx._gb->getVLC2(_ctx._mbVlc._tab->_table, IVI_VLC_BITS, 1);
+ mvX += IVI_TOSIGNED(mvDelta);
+ mb->_mvX = mvX;
+ mb->_mvY = mvY;
+ }
+ }
+ }
+
+ s = band->_isHalfpel;
+ if (mb->_type)
+ if (x + (mb->_mvX >> s) + (y + (mb->_mvY >> s)) * band->_pitch < 0 ||
+ x + ((mb->_mvX + s) >> s) + band->_mbSize - 1
+ + (y + band->_mbSize - 1 + ((mb->_mvY + s) >> s)) * band->_pitch > band->_bufSize - 1) {
+ warning("motion vector %d %d outside reference", x*s + mb->_mvX, y * s + mb->_mvY);
+ return -1;
+ }
+
+ mb++;
+ if (refMb)
+ refMb++;
+ mbOffset += band->_mbSize;
+ }
+
+ offs += rowOffset;
+ }
+
+ _ctx._gb->align();
+
+ return 0;
+}
+
+int Indeo5Decoder::decode_gop_header() {
+ int result, i, p, tileSize, picSizeIndx, mbSize, blkSize, isScalable;
+ int quantMat;
+ bool blkSizeChanged = false;
+ IVIBandDesc *band, *band1, *band2;
+ IVIPicConfig picConf;
+
+ _ctx._gopFlags = _ctx._gb->getBits(8);
+
+ _ctx._gopHdrSize = (_ctx._gopFlags & 1) ? _ctx._gb->getBits(16) : 0;
+
+ if (_ctx._gopFlags & IVI5_IS_PROTECTED)
+ _ctx._lockWord = _ctx._gb->getBits(32);
+
+ tileSize = (_ctx._gopFlags & 0x40) ? 64 << _ctx._gb->getBits(2) : 0;
+ if (tileSize > 256) {
+ warning("Invalid tile size: %d", tileSize);
+ return -1;
+ }
+
+ // decode number of wavelet bands
+ // num_levels * 3 + 1
+ picConf._lumaBands = _ctx._gb->getBits(2) * 3 + 1;
+ picConf._chromaBands = _ctx._gb->getBit() * 3 + 1;
+ isScalable = picConf._lumaBands != 1 || picConf._chromaBands != 1;
+ if (isScalable && (picConf._lumaBands != 4 || picConf._chromaBands != 1)) {
+ warning("Scalability: unsupported subdivision! Luma bands: %d, chroma bands: %d",
+ picConf._lumaBands, picConf._chromaBands);
+ return -1;
+ }
+
+ picSizeIndx = _ctx._gb->getBits(4);
+ if (picSizeIndx == IVI5_PIC_SIZE_ESC) {
+ picConf._picHeight = _ctx._gb->getBits(13);
+ picConf._picWidth = _ctx._gb->getBits(13);
+ } else {
+ picConf._picHeight = _commonPicSizes[picSizeIndx * 2 + 1] << 2;
+ picConf._picWidth = _commonPicSizes[picSizeIndx * 2] << 2;
+ }
+
+ if (_ctx._gopFlags & 2) {
+ warning("YV12 picture format");
+ return -2;
+ }
+
+ picConf._chromaHeight = (picConf._picHeight + 3) >> 2;
+ picConf._chromaWidth = (picConf._picWidth + 3) >> 2;
+
+ if (!tileSize) {
+ picConf._tileHeight = picConf._picHeight;
+ picConf._tileWidth = picConf._picWidth;
+ } else {
+ picConf._tileHeight = picConf._tileWidth = tileSize;
+ }
+
+ // check if picture layout was changed and reallocate buffers
+ if (picConf.ivi_pic_config_cmp(_ctx._picConf) || _ctx._gopInvalid) {
+ result = IVIPlaneDesc::initPlanes(_ctx._planes, &picConf, 0);
+ if (result < 0) {
+ warning("Couldn't reallocate color planes!");
+ return result;
+ }
+ _ctx._picConf = picConf;
+ _ctx._isScalable = isScalable;
+ blkSizeChanged = 1; // force reallocation of the internal structures
+ }
+
+ for (p = 0; p <= 1; p++) {
+ for (i = 0; i < (!p ? picConf._lumaBands : picConf._chromaBands); i++) {
+ band = &_ctx._planes[p]._bands[i];
+
+ band->_isHalfpel = _ctx._gb->getBit();
+
+ mbSize = _ctx._gb->getBit();
+ blkSize = 8 >> _ctx._gb->getBit();
+ mbSize = blkSize << (!mbSize ? 1 : 0);
+
+ if (p == 0 && blkSize == 4) {
+ warning("4x4 luma blocks are unsupported!");
+ return -2;
+ }
+
+ blkSizeChanged = mbSize != band->_mbSize || blkSize != band->_blkSize;
+ if (blkSizeChanged) {
+ band->_mbSize = mbSize;
+ band->_blkSize = blkSize;
+ }
+
+ if (_ctx._gb->getBit()) {
+ warning("Extended transform info");
+ return -2;
+ }
+
+ // select transform function and scan pattern according to plane and band number
+ switch ((p << 2) + i) {
+ case 0:
+ band->_invTransform = IndeoDSP::ffIviInverseSlant8x8;
+ band->_dcTransform = IndeoDSP::ffIviDcSlant2d;
+ band->_scan = ffZigZagDirect;
+ band->_transformSize = 8;
+ break;
+
+ case 1:
+ band->_invTransform = IndeoDSP::ffIviRowSlant8;
+ band->_dcTransform = IndeoDSP::ffIviDcRowSlant;
+ band->_scan = _ffIviVerticalScan8x8;
+ band->_transformSize = 8;
+ break;
+
+ case 2:
+ band->_invTransform = IndeoDSP::ffIviColSlant8;
+ band->_dcTransform = IndeoDSP::ffIviDcColSlant;
+ band->_scan = _ffIviHorizontalScan8x8;
+ band->_transformSize = 8;
+ break;
+
+ case 3:
+ band->_invTransform = IndeoDSP::ffIviPutPixels8x8;
+ band->_dcTransform = IndeoDSP::ffIviPutDcPixel8x8;
+ band->_scan = _ffIviHorizontalScan8x8;
+ band->_transformSize = 8;
+ break;
+
+ case 4:
+ band->_invTransform = IndeoDSP::ffIviInverseSlant4x4;
+ band->_dcTransform = IndeoDSP::ffIviDcSlant2d;
+ band->_scan = _ffIviDirectScan4x4;
+ band->_transformSize = 4;
+ break;
+ }
+
+ band->_is2dTrans = band->_invTransform == IndeoDSP::ffIviInverseSlant8x8 ||
+ band->_invTransform == IndeoDSP::ffIviInverseSlant4x4;
+
+ if (band->_transformSize != band->_blkSize) {
+ warning("transform and block size mismatch (%d != %d)", band->_transformSize, band->_blkSize);
+ return -1;
+ }
+
+ // select dequant matrix according to plane and band number
+ if (!p) {
+ quantMat = (picConf._lumaBands > 1) ? i + 1 : 0;
+ } else {
+ quantMat = 5;
+ }
+
+ if (band->_blkSize == 8) {
+ if (quantMat >= 5) {
+ warning("_quantMat %d too large!", quantMat);
+ return -1;
+ }
+ band->_intraBase = &_baseQuant8x8Intra[quantMat][0];
+ band->_interBase = &_baseQuant8x8Inter[quantMat][0];
+ band->_intraScale = &_scaleQuant8x8Intra[quantMat][0];
+ band->_interScale = &_scaleQuant8x8Inter[quantMat][0];
+ } else {
+ band->_intraBase = _baseQuant4x4Intra;
+ band->_interBase = _baseQuant4x4Inter;
+ band->_intraScale = _scaleQuant4x4Intra;
+ band->_interScale = _scaleQuant4x4Inter;
+ }
+
+ if (_ctx._gb->getBits(2)) {
+ warning("End marker missing!");
+ return -1;
+ }
+ }
+ }
+
+ // copy chroma parameters into the 2nd chroma plane
+ for (i = 0; i < picConf._chromaBands; i++) {
+ band1 = &_ctx._planes[1]._bands[i];
+ band2 = &_ctx._planes[2]._bands[i];
+
+ band2->_width = band1->_width;
+ band2->_height = band1->_height;
+ band2->_mbSize = band1->_mbSize;
+ band2->_blkSize = band1->_blkSize;
+ band2->_isHalfpel = band1->_isHalfpel;
+ band2->_intraBase = band1->_intraBase;
+ band2->_interBase = band1->_interBase;
+ band2->_intraScale = band1->_intraScale;
+ band2->_interScale = band1->_interScale;
+ band2->_scan = band1->_scan;
+ band2->_invTransform = band1->_invTransform;
+ band2->_dcTransform = band1->_dcTransform;
+ band2->_is2dTrans = band1->_is2dTrans;
+ band2->_transformSize = band1->_transformSize;
+ }
+
+ // reallocate internal structures if needed
+ if (blkSizeChanged) {
+ result = IVIPlaneDesc::initTiles(_ctx._planes, picConf._tileWidth,
+ picConf._tileHeight);
+ if (result < 0) {
+ warning("Couldn't reallocate internal structures!");
+ return result;
+ }
+ }
+
+ if (_ctx._gopFlags & 8) {
+ if (_ctx._gb->getBits(3)) {
+ warning("Alignment bits are not zero!");
+ return -1;
+ }
+
+ if (_ctx._gb->getBit())
+ _ctx._gb->skip(24); // skip transparency fill color
+ }
+
+ _ctx._gb->align();
+
+ _ctx._gb->skip(23); // FIXME: unknown meaning
+
+ // skip GOP extension if any
+ if (_ctx._gb->getBit()) {
+ do {
+ i = _ctx._gb->getBits(16);
+ } while (i & 0x8000);
+ }
+
+ _ctx._gb->align();
+
+ return 0;
+}
+
+int Indeo5Decoder::skip_hdr_extension() {
+ int i, len;
+
+ do {
+ len = _ctx._gb->getBits(8);
+ if (_ctx._gb->eos())
+ return -1;
+ for (i = 0; i < len; i++)
+ _ctx._gb->skip(8);
+ } while (len);
+
+ return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+const uint8 Indeo5Decoder::_commonPicSizes[30] = {
+ 160, 120, 80, 60, 40, 30, 176, 120, 88, 60, 88, 72, 44, 36, 60, 45, 160, 60,
+ 176, 60, 20, 15, 22, 18, 0, 0, 0, 0, 0, 0
+};
+
+const uint16 Indeo5Decoder::_baseQuant8x8Inter[5][64] = {
+ {0x26, 0x3a, 0x3e, 0x46, 0x4a, 0x4e, 0x52, 0x5a, 0x3a, 0x3e, 0x42, 0x46, 0x4a, 0x4e, 0x56, 0x5e,
+ 0x3e, 0x42, 0x46, 0x48, 0x4c, 0x52, 0x5a, 0x62, 0x46, 0x46, 0x48, 0x4a, 0x4e, 0x56, 0x5e, 0x66,
+ 0x4a, 0x4a, 0x4c, 0x4e, 0x52, 0x5a, 0x62, 0x6a, 0x4e, 0x4e, 0x52, 0x56, 0x5a, 0x5e, 0x66, 0x6e,
+ 0x52, 0x56, 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x72, 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x6e, 0x72, 0x76,
+ },
+ {0x26, 0x3a, 0x3e, 0x46, 0x4a, 0x4e, 0x52, 0x5a, 0x3a, 0x3e, 0x42, 0x46, 0x4a, 0x4e, 0x56, 0x5e,
+ 0x3e, 0x42, 0x46, 0x48, 0x4c, 0x52, 0x5a, 0x62, 0x46, 0x46, 0x48, 0x4a, 0x4e, 0x56, 0x5e, 0x66,
+ 0x4a, 0x4a, 0x4c, 0x4e, 0x52, 0x5a, 0x62, 0x6a, 0x4e, 0x4e, 0x52, 0x56, 0x5a, 0x5e, 0x66, 0x6e,
+ 0x52, 0x56, 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x72, 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x6e, 0x72, 0x76,
+ },
+ {0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2, 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+ 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2, 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+ 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2, 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+ 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2, 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+ },
+ {0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4,
+ 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2,
+ 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2,
+ },
+ {0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+ 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+ 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+ 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+ }
+};
+
+const uint16 Indeo5Decoder::_baseQuant8x8Intra[5][64] = {
+ {0x1a, 0x2e, 0x36, 0x42, 0x46, 0x4a, 0x4e, 0x5a, 0x2e, 0x32, 0x3e, 0x42, 0x46, 0x4e, 0x56, 0x6a,
+ 0x36, 0x3e, 0x3e, 0x44, 0x4a, 0x54, 0x66, 0x72, 0x42, 0x42, 0x44, 0x4a, 0x52, 0x62, 0x6c, 0x7a,
+ 0x46, 0x46, 0x4a, 0x52, 0x5e, 0x66, 0x72, 0x8e, 0x4a, 0x4e, 0x54, 0x62, 0x66, 0x6e, 0x86, 0xa6,
+ 0x4e, 0x56, 0x66, 0x6c, 0x72, 0x86, 0x9a, 0xca, 0x5a, 0x6a, 0x72, 0x7a, 0x8e, 0xa6, 0xca, 0xfe,
+ },
+ {0x26, 0x3a, 0x3e, 0x46, 0x4a, 0x4e, 0x52, 0x5a, 0x3a, 0x3e, 0x42, 0x46, 0x4a, 0x4e, 0x56, 0x5e,
+ 0x3e, 0x42, 0x46, 0x48, 0x4c, 0x52, 0x5a, 0x62, 0x46, 0x46, 0x48, 0x4a, 0x4e, 0x56, 0x5e, 0x66,
+ 0x4a, 0x4a, 0x4c, 0x4e, 0x52, 0x5a, 0x62, 0x6a, 0x4e, 0x4e, 0x52, 0x56, 0x5a, 0x5e, 0x66, 0x6e,
+ 0x52, 0x56, 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x72, 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x6e, 0x72, 0x76,
+ },
+ {0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2, 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+ 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2, 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+ 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2, 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+ 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2, 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+ },
+ {0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4,
+ 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2,
+ 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2,
+ },
+ {0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+ 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+ 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+ 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+ }
+};
+
+const uint16 Indeo5Decoder::_baseQuant4x4Inter[16] = {
+ 0x1e, 0x3e, 0x4a, 0x52, 0x3e, 0x4a, 0x52, 0x56, 0x4a, 0x52, 0x56, 0x5e, 0x52, 0x56, 0x5e, 0x66
+};
+
+const uint16 Indeo5Decoder::_baseQuant4x4Intra[16] = {
+ 0x1e, 0x3e, 0x4a, 0x52, 0x3e, 0x4a, 0x52, 0x5e, 0x4a, 0x52, 0x5e, 0x7a, 0x52, 0x5e, 0x7a, 0x92
+};
+
+
+const uint8 Indeo5Decoder::_scaleQuant8x8Inter[5][24] = {
+ {0x0b, 0x11, 0x13, 0x14, 0x15, 0x16, 0x18, 0x1a, 0x1b, 0x1d, 0x20, 0x22,
+ 0x23, 0x25, 0x28, 0x2a, 0x2e, 0x32, 0x35, 0x39, 0x3d, 0x41, 0x44, 0x4a,
+ },
+ {0x07, 0x14, 0x16, 0x18, 0x1b, 0x1e, 0x22, 0x25, 0x29, 0x2d, 0x31, 0x35,
+ 0x3a, 0x3f, 0x44, 0x4a, 0x50, 0x56, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x7e,
+ },
+ {0x15, 0x25, 0x28, 0x2d, 0x30, 0x34, 0x3a, 0x3d, 0x42, 0x48, 0x4c, 0x51,
+ 0x56, 0x5b, 0x60, 0x65, 0x6b, 0x70, 0x76, 0x7c, 0x82, 0x88, 0x8f, 0x97,
+ },
+ {0x13, 0x1f, 0x20, 0x22, 0x25, 0x28, 0x2b, 0x2d, 0x30, 0x33, 0x36, 0x39,
+ 0x3c, 0x3f, 0x42, 0x45, 0x48, 0x4b, 0x4e, 0x52, 0x56, 0x5a, 0x5e, 0x62,
+ },
+ {0x3c, 0x52, 0x58, 0x5d, 0x63, 0x68, 0x68, 0x6d, 0x73, 0x78, 0x7c, 0x80,
+ 0x84, 0x89, 0x8e, 0x93, 0x98, 0x9d, 0xa3, 0xa9, 0xad, 0xb1, 0xb5, 0xba,
+ },
+};
+
+const uint8 Indeo5Decoder::_scaleQuant8x8Intra[5][24] = {
+ {0x0b, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x17, 0x18, 0x1a, 0x1c, 0x1e, 0x20,
+ 0x22, 0x24, 0x27, 0x28, 0x2a, 0x2d, 0x2f, 0x31, 0x34, 0x37, 0x39, 0x3c,
+ },
+ {0x01, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1b, 0x1e, 0x22, 0x25, 0x28, 0x2c,
+ 0x30, 0x34, 0x38, 0x3d, 0x42, 0x47, 0x4c, 0x52, 0x58, 0x5e, 0x65, 0x6c,
+ },
+ {0x13, 0x22, 0x27, 0x2a, 0x2d, 0x33, 0x36, 0x3c, 0x41, 0x45, 0x49, 0x4e,
+ 0x53, 0x58, 0x5d, 0x63, 0x69, 0x6f, 0x75, 0x7c, 0x82, 0x88, 0x8e, 0x95,
+ },
+ {0x13, 0x1f, 0x21, 0x24, 0x27, 0x29, 0x2d, 0x2f, 0x34, 0x37, 0x3a, 0x3d,
+ 0x40, 0x44, 0x48, 0x4c, 0x4f, 0x52, 0x56, 0x5a, 0x5e, 0x62, 0x66, 0x6b,
+ },
+ {0x31, 0x42, 0x47, 0x47, 0x4d, 0x52, 0x58, 0x58, 0x5d, 0x63, 0x67, 0x6b,
+ 0x6f, 0x73, 0x78, 0x7c, 0x80, 0x84, 0x89, 0x8e, 0x93, 0x98, 0x9d, 0xa4,
+ }
+};
+
+const uint8 Indeo5Decoder::_scaleQuant4x4Inter[24] = {
+ 0x0b, 0x0d, 0x0d, 0x0e, 0x11, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+};
+
+const uint8 Indeo5Decoder::_scaleQuant4x4Intra[24] = {
+ 0x01, 0x0b, 0x0b, 0x0d, 0x0d, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20
+};
+
+} // End of namespace Image
diff --git a/image/codecs/indeo5.h b/image/codecs/indeo5.h
new file mode 100644
index 0000000000..704bda5e4b
--- /dev/null
+++ b/image/codecs/indeo5.h
@@ -0,0 +1,136 @@
+/* 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.
+ *
+ */
+
+/* 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_INDEO5_H
+#define IMAGE_CODECS_INDEO5_H
+
+#include "image/codecs/indeo/get_bits.h"
+#include "image/codecs/indeo/indeo.h"
+
+namespace Image {
+
+using namespace Indeo;
+
+/**
+ * Intel Indeo 5 decoder.
+ *
+ * Used by AVI.
+ *
+ * Used in video:
+ * - AVIDecoder
+ */
+class Indeo5Decoder : public IndeoDecoderBase {
+ struct Transform {
+ InvTransformPtr *inv_trans;
+ DCTransformPtr *dc_trans;
+ int is_2d_trans;
+ };
+public:
+ Indeo5Decoder(uint16 width, uint16 height);
+ virtual ~Indeo5Decoder() {}
+
+ virtual const Graphics::Surface *decodeFrame(Common::SeekableReadStream &stream);
+
+ static bool isIndeo5(Common::SeekableReadStream &stream);
+protected:
+ /**
+ * Decode the Indeo 5 picture header.
+ * @returns 0 = Ok, negative number = error
+ */
+ virtual int decodePictureHeader();
+
+ /**
+ * Rearrange decoding and reference buffers.
+ */
+ virtual void switchBuffers();
+
+ virtual bool isNonNullFrame() const;
+
+ /**
+ * Decode Indeo 4 band header.
+ *
+ * @param[in,out] band pointer to the band descriptor
+ * @return result code: 0 = OK, negative number = error
+ */
+ virtual int decodeBandHeader(IVIBandDesc *band);
+
+ /**
+ * 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
+ * @return result code: 0 = OK, negative number = error
+ */
+ virtual int decodeMbInfo(IVIBandDesc *band, IVITile *tile);
+private:
+ /**
+ * Decode Indeo5 GOP (Group of pictures) header.
+ * This header is present in key frames only.
+ * It defines parameters for all frames in a GOP.
+ * @returns result code: 0 = OK, -1 = error
+ */
+ int decode_gop_header();
+
+ /**
+ * Skip a header extension.
+ */
+ int skip_hdr_extension();
+
+private:
+ /**
+ * standard picture dimensions (width, height divided by 4)
+ */
+ static const uint8 _commonPicSizes[30];
+
+ /**
+ * Indeo5 dequantization matrixes consist of two tables: base table
+ * and scale table. The base table defines the dequantization matrix
+ * itself and the scale table tells how this matrix should be scaled
+ * for a particular quant level (0...24).
+ *
+ * ivi5_base_quant_bbb_ttt - base tables for block size 'bbb' of type 'ttt'
+ * ivi5_scale_quant_bbb_ttt - scale tables for block size 'bbb' of type 'ttt'
+ */
+ static const uint16 _baseQuant8x8Inter[5][64];
+ static const uint16 _baseQuant8x8Intra[5][64];
+
+ static const uint16 _baseQuant4x4Inter[16];
+ static const uint16 _baseQuant4x4Intra[16];
+
+ static const uint8 _scaleQuant8x8Inter[5][24];
+ static const uint8 _scaleQuant8x8Intra[5][24];
+
+ static const uint8 _scaleQuant4x4Inter[24];
+ static const uint8 _scaleQuant4x4Intra[24];
+};
+
+} // End of namespace Image
+
+#endif
diff --git a/image/module.mk b/image/module.mk
index 3742fb909f..2ede7c3bdb 100644
--- a/image/module.mk
+++ b/image/module.mk
@@ -13,6 +13,8 @@ MODULE_OBJS := \
codecs/cinepak.o \
codecs/codec.o \
codecs/indeo3.o \
+ codecs/indeo4.o \
+ codecs/indeo5.o \
codecs/mjpeg.o \
codecs/msrle.o \
codecs/msrle4.o \
@@ -21,7 +23,12 @@ MODULE_OBJS := \
codecs/rpza.o \
codecs/smc.o \
codecs/svq1.o \
- codecs/truemotion1.o
+ codecs/truemotion1.o \
+ codecs/indeo/get_bits.o \
+ codecs/indeo/indeo.o \
+ codecs/indeo/indeo_dsp.o \
+ codecs/indeo/mem.o \
+ codecs/indeo/vlc.o
ifdef USE_MPEG2
MODULE_OBJS += \