aboutsummaryrefslogtreecommitdiff
path: root/image/codecs/indeo
diff options
context:
space:
mode:
authorEugene Sandulenko2016-09-11 16:58:54 +0200
committerGitHub2016-09-11 16:58:54 +0200
commit0733cf65ba8f6babdf35547b49cd2d57c9daf646 (patch)
tree61c24edbc0a1080711c93c674b9848f4a16efb50 /image/codecs/indeo
parent49bc276ea3e297c23098d4f0e6ab331f0b89f6ee (diff)
parent08143af48293b007027d11271d3f66f7ad3107e6 (diff)
downloadscummvm-rg350-0733cf65ba8f6babdf35547b49cd2d57c9daf646.tar.gz
scummvm-rg350-0733cf65ba8f6babdf35547b49cd2d57c9daf646.tar.bz2
scummvm-rg350-0733cf65ba8f6babdf35547b49cd2d57c9daf646.zip
Merge pull request #826 from dreammaster/indeo
IMAGE: Indeo 4 & 5 decoders
Diffstat (limited to 'image/codecs/indeo')
-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
10 files changed, 4207 insertions, 0 deletions
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