aboutsummaryrefslogtreecommitdiff
path: root/image
diff options
context:
space:
mode:
authorPaul Gilbert2016-09-05 23:00:08 -0400
committerPaul Gilbert2016-09-10 10:08:10 -0400
commit5f0962696f97df2cce27d065d99b04243de59334 (patch)
tree001c83f1550677226cf264d6dc6a3c9ceaa70e2f /image
parent73e79031865a71dd5ced18fe3269f79ceba6e08c (diff)
downloadscummvm-rg350-5f0962696f97df2cce27d065d99b04243de59334.tar.gz
scummvm-rg350-5f0962696f97df2cce27d065d99b04243de59334.tar.bz2
scummvm-rg350-5f0962696f97df2cce27d065d99b04243de59334.zip
IMAGE: Added Indeo4Decoder decodePictureHeader, and lots of dependencies
Diffstat (limited to 'image')
-rw-r--r--image/codecs/indeo/get_bits.cpp24
-rw-r--r--image/codecs/indeo/get_bits.h19
-rw-r--r--image/codecs/indeo/indeo.cpp394
-rw-r--r--image/codecs/indeo/indeo.h350
-rw-r--r--image/codecs/indeo/mem.cpp157
-rw-r--r--image/codecs/indeo/mem.h145
-rw-r--r--image/codecs/indeo/vlc.cpp336
-rw-r--r--image/codecs/indeo/vlc.h138
-rw-r--r--image/codecs/indeo4.cpp198
-rw-r--r--image/codecs/indeo4.h32
-rw-r--r--image/module.mk5
11 files changed, 1788 insertions, 10 deletions
diff --git a/image/codecs/indeo/get_bits.cpp b/image/codecs/indeo/get_bits.cpp
index 4878bc674f..98cef7facd 100644
--- a/image/codecs/indeo/get_bits.cpp
+++ b/image/codecs/indeo/get_bits.cpp
@@ -21,6 +21,7 @@
*/
#include "image/codecs/indeo/get_bits.h"
+#include "common/algorithm.h"
#include "common/endian.h"
#include "common/textconsole.h"
@@ -160,14 +161,35 @@ GetBits::GetBits(const byte *buffer, size_t totalBits) {
assert(buffer && totalBits < (INT_MAX - 7));
_buffer = buffer;
+ _disposeAfterUse = DisposeAfterUse::NO;
_sizeInBits = totalBits;
_sizeInBitsPlus8 = totalBits + 8;
_index = 0;
}
+GetBits::GetBits(Common::SeekableReadStream &stream) {
+ byte *buffer = new byte[stream.size()];
+ stream.read(buffer, stream.size());
+ _buffer = buffer;
+ _disposeAfterUse = DisposeAfterUse::YES;
+ _sizeInBits = stream.size() * 8;
+ _sizeInBitsPlus8 = _sizeInBits + 8;
+ _index = 0;
+}
GetBits::GetBits(const GetBits &src) : _index(src._index), _buffer(src._buffer),
- _sizeInBits(src._sizeInBits), _sizeInBitsPlus8(src._sizeInBitsPlus8) {
+ _sizeInBits(src._sizeInBits), _sizeInBitsPlus8(src._sizeInBitsPlus8),
+ _disposeAfterUse(src._disposeAfterUse) {
+ if (_disposeAfterUse == DisposeAfterUse::YES) {
+ byte *buffer = new byte[src._sizeInBits / 8];
+ Common::copy(src._buffer, src._buffer + (src._sizeInBits / 8), buffer);
+ _buffer = buffer;
+ }
+}
+
+GetBits::~GetBits() {
+ if (_disposeAfterUse == DisposeAfterUse::YES)
+ delete[] _buffer;
}
int GetBits::getXbits(int n) {
diff --git a/image/codecs/indeo/get_bits.h b/image/codecs/indeo/get_bits.h
index dd6ba55dd2..313fe7e2da 100644
--- a/image/codecs/indeo/get_bits.h
+++ b/image/codecs/indeo/get_bits.h
@@ -32,6 +32,8 @@
#define IMAGE_CODECS_INDEO_GET_BITS_H
#include "common/scummsys.h"
+#include "common/stream.h"
+#include "common/types.h"
namespace Image {
namespace Indeo {
@@ -44,13 +46,14 @@ namespace Indeo {
class GetBits {
private:
const byte *_buffer;
+ DisposeAfterUse::Flag _disposeAfterUse;
uint _index;
uint _sizeInBits;
uint _sizeInBitsPlus8;
public:
/**
* Constructor
- * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes
+ * @param buffer Bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes
* larger than the actual read bits because some optimized bitstream
* readers read 32 or 64 bit at once and could read over the end
* @param bit_size the size of the buffer in bits
@@ -58,9 +61,23 @@ public:
*/
GetBits(const byte *buffer, size_t totalBits);
+ /**
+ * Constructor
+ * @param stream Stream to get data from
+ */
+ GetBits(Common::SeekableReadStream &stream);
+
+ /**
+ * Copy constructor
+ */
GetBits(const GetBits &src);
/**
+ * Destructor
+ */
+ ~GetBits();
+
+ /**
* Returns the number of bits read
*/
uint getBitsCount() const { return _index; }
diff --git a/image/codecs/indeo/indeo.cpp b/image/codecs/indeo/indeo.cpp
new file mode 100644
index 0000000000..9de32fa301
--- /dev/null
+++ b/image/codecs/indeo/indeo.cpp
@@ -0,0 +1,394 @@
+/* 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 and macros 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/mem.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, tile_size) (((stride) + (tile_size) - 1) / (tile_size))
+
+
+/**
+ * calculate number of macroblocks in a tile
+ */
+#define IVI_MBs_PER_TILE(tile_width, tile_height, mb_size) \
+ ((((tile_width) + (mb_size) - 1) / (mb_size)) * (((tile_height) + (mb_size) - 1) / (mb_size)))
+
+/*------------------------------------------------------------------------*/
+
+int IVIHuffDesc::ivi_create_huff_from_desc(VLC *vlc, int flag) const {
+ int pos, i, j, codes_per_row, prefix, not_last_row;
+ uint16 codewords[256];
+ uint8 bits[256];
+
+ pos = 0; // current position = 0
+
+ for (i = 0; i < num_rows; i++) {
+ codes_per_row = 1 << xbits[i];
+ not_last_row = (i != num_rows - 1);
+ prefix = ((1 << i) - 1) << (xbits[i] + not_last_row);
+
+ for (j = 0; j < codes_per_row; 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] + not_last_row;
+ if (bits[pos] > IVI_VLC_BITS)
+ return -1; // invalid descriptor
+
+ codewords[pos] = inv_bits((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::ivi_huff_desc_cmp(const IVIHuffDesc *desc2) const {
+ return num_rows != desc2->num_rows ||
+ memcmp(xbits, desc2->xbits, num_rows);
+}
+
+void IVIHuffDesc::ivi_huff_desc_copy(const IVIHuffDesc *src) {
+ num_rows = src->num_rows;
+ memcpy(xbits, src->xbits, src->num_rows);
+}
+
+/*------------------------------------------------------------------------*/
+
+IVIHuffTab::IVIHuffTab() {
+ tab = nullptr;
+
+ for (int i = 0; i < 8; i++) {
+ ivi_mb_vlc_tabs[i].table = table_data + i * 2 * 8192;
+ ivi_mb_vlc_tabs[i].table_allocated = 8192;
+ ivi_mb_huff_desc[i].ivi_create_huff_from_desc(&ivi_mb_vlc_tabs[i], 1);
+ ivi_blk_vlc_tabs[i].table = table_data + (i * 2 + 1) * 8192;
+ ivi_blk_vlc_tabs[i].table_allocated = 8192;
+ ivi_blk_huff_desc[i].ivi_create_huff_from_desc(&ivi_blk_vlc_tabs[i], 1);
+ }
+}
+
+int IVIHuffTab::ff_ivi_dec_huff_desc(GetBits *gb, int desc_coded, int which_tab) {
+ int i, result;
+ IVIHuffDesc new_huff;
+
+ if (!desc_coded) {
+ // select default table
+ tab = (which_tab) ? &ivi_blk_vlc_tabs[7]
+ : &ivi_mb_vlc_tabs[7];
+ return 0;
+ }
+
+ tab_sel = gb->getBits(3);
+ if (tab_sel == 7) {
+ // custom huffman table (explicitly encoded)
+ new_huff.num_rows = gb->getBits(4);
+ if (!new_huff.num_rows) {
+ warning("Empty custom Huffman table!");
+ return -1;
+ }
+
+ for (i = 0; i < new_huff.num_rows; i++)
+ new_huff.xbits[i] = gb->getBits(4);
+
+ // Have we got the same custom table? Rebuild if not.
+ if (new_huff.ivi_huff_desc_cmp(&cust_desc) || !cust_tab.table) {
+ cust_desc.ivi_huff_desc_copy(&new_huff);
+
+ if (cust_tab.table)
+ cust_tab.ff_free_vlc();
+ result = cust_desc.ivi_create_huff_from_desc(&cust_tab, 0);
+ if (result) {
+ // reset faulty description
+ cust_desc.num_rows = 0;
+ warning("Error while initializing custom vlc table!");
+ return result;
+ }
+ }
+ tab = &cust_tab;
+ } else {
+ // select one of predefined tables
+ tab = (which_tab) ? &ivi_blk_vlc_tabs[tab_sel]
+ : &ivi_mb_vlc_tabs[tab_sel];
+ }
+
+ return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+bool IVIPicConfig::ivi_pic_config_cmp(const IVIPicConfig &cfg2) {
+ return pic_width != cfg2.pic_width || pic_height != cfg2.pic_height ||
+ chroma_width != cfg2.chroma_width || chroma_height != cfg2.chroma_height ||
+ tile_width != cfg2.tile_width || tile_height != cfg2.tile_height ||
+ luma_bands != cfg2.luma_bands || chroma_bands != cfg2.chroma_bands;
+}
+
+/*------------------------------------------------------------------------*/
+
+int IVIPlaneDesc::ff_ivi_init_planes(IVIPlaneDesc *planes, const IVIPicConfig *cfg, bool is_indeo4) {
+ int p, b;
+ uint32 b_width, b_height, align_fac, width_aligned,
+ height_aligned, buf_size;
+ IVIBandDesc *band;
+
+ ivi_free_buffers(planes);
+
+ if (av_image_check_size(cfg->pic_width, cfg->pic_height, 0, NULL) < 0 ||
+ cfg->luma_bands < 1 || cfg->chroma_bands < 1)
+ return -1;
+
+ // fill in the descriptor of the luminance plane
+ planes[0].width = cfg->pic_width;
+ planes[0].height = cfg->pic_height;
+ planes[0].num_bands = cfg->luma_bands;
+
+ // fill in the descriptors of the chrominance planes
+ planes[1].width = planes[2].width = (cfg->pic_width + 3) >> 2;
+ planes[1].height = planes[2].height = (cfg->pic_height + 3) >> 2;
+ planes[1].num_bands = planes[2].num_bands = cfg->chroma_bands;
+
+ for (p = 0; p < 3; p++) {
+ planes[p].bands = (IVIBandDesc *)av_mallocz_array(planes[p].num_bands, 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].num_bands == 1 ? planes[p].width
+ : (planes[p].width + 1) >> 1;
+ b_height = planes[p].num_bands == 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);
+ buf_size = width_aligned * height_aligned * sizeof(int16);
+
+ for (b = 0; b < planes[p].num_bands; b++) {
+ band = &planes[p].bands[b]; // select appropriate plane/band
+ band->plane = p;
+ band->band_num = b;
+ band->width = b_width;
+ band->height = b_height;
+ band->pitch = width_aligned;
+ band->aheight = height_aligned;
+ band->bufs[0] = (int16 *)av_mallocz(buf_size);
+ band->bufs[1] = (int16 *)av_mallocz(buf_size);
+ band->bufsize = buf_size / 2;
+ if (!band->bufs[0] || !band->bufs[1])
+ return -2;
+
+ // allocate the 3rd band buffer for scalability mode
+ if (cfg->luma_bands > 1) {
+ band->bufs[2] = (int16 *)av_mallocz(buf_size);
+ if (!band->bufs[2])
+ return -2;
+ }
+ if (is_indeo4) {
+ band->bufs[3] = (int16 *)av_mallocz(buf_size);
+ if (!band->bufs[3])
+ return -2;
+ }
+ // reset custom vlc
+ planes[p].bands[0].blk_vlc.cust_desc.num_rows = 0;
+ }
+ }
+
+ return 0;
+}
+
+int IVIPlaneDesc::ff_ivi_init_tiles(IVIPlaneDesc *planes,
+ int tile_width, int tile_height) {
+ int p, b, x_tiles, y_tiles, t_width, t_height, ret;
+ IVIBandDesc *band;
+
+ for (p = 0; p < 3; p++) {
+ t_width = !p ? tile_width : (tile_width + 3) >> 2;
+ t_height = !p ? tile_height : (tile_height + 3) >> 2;
+
+ if (!p && planes[0].num_bands == 4) {
+ t_width >>= 1;
+ t_height >>= 1;
+ }
+ if (t_width <= 0 || t_height <= 0)
+ return -3;
+
+ for (b = 0; b < planes[p].num_bands; b++) {
+ band = &planes[p].bands[b];
+ x_tiles = IVI_NUM_TILES(band->width, t_width);
+ y_tiles = IVI_NUM_TILES(band->height, t_height);
+ band->num_tiles = x_tiles * y_tiles;
+
+ av_freep(&band->tiles);
+ band->tiles = (IVITile *)av_mallocz_array(band->num_tiles, sizeof(IVITile));
+ if (!band->tiles)
+ return -2;
+
+ // use the first luma band as reference for motion vectors
+ // and quant
+ ret = band->ivi_init_tiles(planes[0].bands[0].tiles,
+ p, b, t_height, t_width);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+void IVIPlaneDesc::ivi_free_buffers(IVIPlaneDesc *planes) {
+ int p, b, t;
+
+ for (p = 0; p < 3; p++) {
+ if (planes[p].bands)
+ for (b = 0; b < planes[p].num_bands; b++) {
+ av_freep(&planes[p].bands[b].bufs[0]);
+ av_freep(&planes[p].bands[b].bufs[1]);
+ av_freep(&planes[p].bands[b].bufs[2]);
+ av_freep(&planes[p].bands[b].bufs[3]);
+
+ if (planes[p].bands[b].blk_vlc.cust_tab.table)
+ planes[p].bands[b].blk_vlc.cust_tab.ff_free_vlc();
+ for (t = 0; t < planes[p].bands[b].num_tiles; t++)
+ av_freep(&planes[p].bands[b].tiles[t].mbs);
+ av_freep(&planes[p].bands[b].tiles);
+ }
+ av_freep(&planes[p].bands);
+ planes[p].num_bands = 0;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+int IVIBandDesc::ivi_init_tiles(IVITile *ref_tile, int p, int b, int t_height, int t_width) {
+ int x, y;
+ IVITile *tile = tiles;
+
+ for (y = 0; y < height; y += t_height) {
+ for (x = 0; x < width; x += t_width) {
+ tile->xpos = x;
+ tile->ypos = y;
+ tile->mb_size = mb_size;
+ tile->width = MIN(width - x, t_width);
+ tile->height = MIN(height - y, t_height);
+ tile->is_empty = tile->data_size = 0;
+ // calculate number of macroblocks
+ tile->num_MBs = IVI_MBs_PER_TILE(tile->width, tile->height,
+ mb_size);
+
+ av_freep(&tile->mbs);
+ tile->mbs = (IVIMbInfo *)av_mallocz_array(tile->num_MBs, sizeof(IVIMbInfo));
+ if (!tile->mbs)
+ return -2;
+
+ tile->ref_mbs = 0;
+ if (p || b) {
+ if (tile->num_MBs != ref_tile->num_MBs) {
+ warning("ref_tile mismatch");
+ return -1;
+ }
+ tile->ref_mbs = ref_tile->mbs;
+ ref_tile++;
+ }
+ tile++;
+ }
+ }
+
+ return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx) {
+ if (((w + 128) * (uint64)(h + 128)) < (INT_MAX / 8))
+ return 0;
+
+ error("Picture size %ux%u is invalid", w, h);
+}
+
+} // 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..d689994b03
--- /dev/null
+++ b/image/codecs/indeo/indeo.h
@@ -0,0 +1,350 @@
+/* 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 structures and macros 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
+};
+
+#define IVI_VLC_BITS 13 ///< max number of bits of the ivi's huffman codes
+#define IVI5_IS_PROTECTED 0x20
+
+/**
+ * huffman codebook descriptor
+ */
+struct IVIHuffDesc {
+ int32 num_rows;
+ 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: 1 - for static or 0 for dynamic tables
+ * @return result code: 0 - OK, -1 = error (invalid codebook descriptor)
+ */
+ int ivi_create_huff_from_desc(VLC *vlc, int flag) const;
+
+ /*
+ * Compare two huffman codebook descriptors.
+ *
+ * @param[in] desc2 ptr to the 2nd descriptor to compare
+ * @return comparison result: 0 - equal, 1 - not equal
+ */
+ bool ivi_huff_desc_cmp(const IVIHuffDesc *desc2) const;
+
+ /*
+ * Copy huffman codebook descriptors.
+ *
+ * @param[in] src ptr to the source descriptor
+ */
+ void ivi_huff_desc_copy(const IVIHuffDesc *src);
+};
+
+/**
+ * macroblock/block huffman table descriptor
+ */
+struct IVIHuffTab {
+private:
+ VLC_TYPE table_data[8192 * 16][2];
+ VLC ivi_mb_vlc_tabs[8]; ///< static macroblock Huffman tables
+ VLC ivi_blk_vlc_tabs[8]; ///< static block Huffman tables
+public:
+ int32 tab_sel; /// 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 cust_desc; /// custom Huffman codebook descriptor
+ VLC cust_tab; /// vlc table for custom codebook
+
+ /**
+ * Constructor
+ */
+ IVIHuffTab();
+
+ int ff_ivi_dec_huff_desc(GetBits *gb, int desc_coded, int which_tab);
+};
+
+enum {
+ IVI_MB_HUFF = 0, /// Huffman table is used for coding macroblocks
+ IVI_BLK_HUFF = 1 /// Huffman table is used for coding blocks
+};
+
+
+/**
+ * Common scan patterns (defined in ivi_common.c)
+ */
+//extern const uint8 ff_ivi_vertical_scan_8x8[64];
+//extern const uint8 ff_ivi_horizontal_scan_8x8[64];
+//extern const uint8 ff_ivi_direct_scan_4x4[16];
+
+
+/**
+ * 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 blk_size);
+
+
+/**
+ * run-value (RLE) table descriptor
+ */
+struct RVMapDesc {
+ uint8 eob_sym; ///< end of block symbol
+ uint8 esc_sym; ///< escape symbol
+ uint8 runtab[256];
+ int8 valtab[256];
+};
+
+extern const RVMapDesc ff_ivi_rvmap_tabs[9];
+
+
+/**
+ * information for Indeo macroblock (16x16, 8x8 or 4x4)
+ */
+struct IVIMbInfo {
+ int16 xpos;
+ int16 ypos;
+ uint32 buf_offs; ///< address in the output buffer for this mb
+ uint8 type; ///< macroblock type: 0 - INTRA, 1 - INTER
+ uint8 cbp; ///< coded block pattern
+ int8 q_delta; ///< quant delta
+ int8 mv_x; ///< motion vector (x component)
+ int8 mv_y; ///< motion vector (y component)
+ int8 b_mv_x; ///< second motion vector (x component)
+ int8 b_mv_y; ///< second motion vector (y component)
+};
+
+
+/**
+ * information for Indeo tile
+ */
+struct IVITile {
+ int xpos;
+ int ypos;
+ int width;
+ int height;
+ int mb_size;
+ int is_empty; ///< = 1 if this tile doesn't contain any data
+ int data_size; ///< size of the data in bytes
+ int num_MBs; ///< number of macroblocks in this tile
+ IVIMbInfo * mbs; ///< array of macroblock descriptors
+ IVIMbInfo * ref_mbs; ///< ptr to the macroblock descriptors of the reference tile
+};
+
+
+/**
+ * information for Indeo wavelet band
+ */
+struct IVIBandDesc {
+ int plane; ///< plane number this band belongs to
+ int band_num; ///< band number
+ int width;
+ int height;
+ int aheight; ///< aligned band height
+ const uint8 * data_ptr; ///< ptr to the first byte of the band data
+ int data_size; ///< size of the band data
+ int16 * buf; ///< pointer to the output buffer for this band
+ int16 * ref_buf; ///< pointer to the reference frame buffer (for motion compensation)
+ int16 * b_ref_buf; ///< 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
+ int is_empty; ///< = 1 if this band doesn't contain any data
+ int mb_size; ///< macroblock size
+ int blk_size; ///< block size
+ int is_halfpel; ///< precision of the motion compensation: 0 - fullpel, 1 - halfpel
+ int inherit_mv; ///< tells if motion vector is inherited from reference macroblock
+ int inherit_qdelta; ///< tells if quantiser delta is inherited from reference macroblock
+ int qdelta_present; ///< tells if Qdelta signal is present in the bitstream (Indeo5 only)
+ int quant_mat; ///< dequant matrix index
+ int glob_quant; ///< quant base for this band
+ const uint8 * scan; ///< ptr to the scan pattern
+ int scan_size; ///< size of the scantable
+
+ IVIHuffTab blk_vlc; ///< vlc table for decoding block data
+
+ int num_corr; ///< number of correction entries
+ uint8 corr[61 * 2]; ///< rvmap correction pairs
+ int rvmap_sel; ///< rvmap table selector
+ RVMapDesc * rv_map; ///< ptr to the RLE table for this band
+ int num_tiles; ///< number of tiles in this band
+ IVITile * tiles; ///< array of tile descriptors
+ InvTransformPtr *inv_transform;
+ int transform_size;
+ DCTransformPtr *dc_transform;
+ int is_2d_trans; ///< 1 indicates that the two-dimensional inverse transform is used
+ int32 checksum; ///< for debug purposes
+ int checksum_present;
+ int bufsize; ///< band buffer size in bytes
+ const uint16 * intra_base; ///< quantization matrix for intra blocks
+ const uint16 * inter_base; ///< quantization matrix for inter blocks
+ const uint8 * intra_scale; ///< quantization coefficient for intra blocks
+ const uint8 * inter_scale; ///< quantization coefficient for inter blocks
+
+ int ivi_init_tiles(IVITile *ref_tile, int p, int b, int t_height, int t_width);
+};
+
+struct IVIPicConfig {
+ uint16 pic_width;
+ uint16 pic_height;
+ uint16 chroma_width;
+ uint16 chroma_height;
+ uint16 tile_width;
+ uint16 tile_height;
+ uint8 luma_bands;
+ uint8 chroma_bands;
+
+ /**
+ * 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 num_bands; ///< number of bands this plane subdivided into
+ IVIBandDesc *bands; ///< array of band descriptors
+
+ static int ff_ivi_init_planes(IVIPlaneDesc *planes, const IVIPicConfig *cfg, bool is_indeo4);
+
+ static int ff_ivi_init_tiles(IVIPlaneDesc *planes, int tile_width, int tile_height);
+
+ /*
+ * Free planes, bands and macroblocks buffers.
+ *
+ * @param[in] planes pointer to the array of the plane descriptors
+ */
+ static void ivi_free_buffers(IVIPlaneDesc *planes);
+};
+
+struct IVI45DecContext {
+ GetBits * gb;
+ RVMapDesc rvmap_tabs[9]; ///< local corrected copy of the static rvmap tables
+
+ uint32 frame_num;
+ int frame_type;
+ int prev_frame_type; ///< frame type of the previous frame
+ uint32 data_size; ///< size of the frame data in bytes from picture header
+ int is_scalable;
+ const uint8 * frame_data; ///< input frame data pointer
+ int inter_scal; ///< signals a sequence of scalable inter frames
+ uint32 frame_size; ///< frame size in bytes
+ uint32 pic_hdr_size; ///< picture header size in bytes
+ uint8 frame_flags;
+ uint16 checksum; ///< frame checksum
+
+ IVIPicConfig pic_conf;
+ IVIPlaneDesc planes[3]; ///< color planes
+
+ int buf_switch; ///< used to switch between three buffers
+ int dst_buf; ///< buffer index for the currently decoded frame
+ int ref_buf; ///< inter frame reference buffer index
+ int ref2_buf; ///< temporal storage for switching buffers
+ int b_ref_buf; ///< second reference frame buffer index
+
+ IVIHuffTab mb_vlc; ///< current macroblock table descriptor
+ IVIHuffTab blk_vlc; ///< current block table descriptor
+
+ uint8 rvmap_sel;
+ uint8 in_imf;
+ uint8 in_q; ///< flag for explicitly stored quantiser delta
+ uint8 pic_glob_quant;
+ uint8 unknown1;
+
+ uint16 gop_hdr_size;
+ uint8 gop_flags;
+ uint32 lock_word;
+
+ int show_indeo4_info;
+ uint8 has_b_frames;
+ uint8 has_transp; ///< transparency mode status: 1 - enabled
+ uint8 uses_tiling;
+ uint8 uses_haar;
+ uint8 uses_fullpel;
+
+// int (*decode_pic_hdr) (struct IVI45DecContext *ctx, AVCodecContext *avctx);
+// int (*decode_band_hdr) (struct IVI45DecContext *ctx, IVIBandDesc *band, AVCodecContext *avctx);
+// int (*decode_mb_info) (struct IVI45DecContext *ctx, IVIBandDesc *band, IVITile *tile, AVCodecContext *avctx);
+// void (*switch_buffers) (struct IVI45DecContext *ctx);
+// int (*is_nonnull_frame)(struct IVI45DecContext *ctx);
+
+ int gop_invalid;
+ int buf_invalid[4];
+
+ int is_indeo4;
+
+// AVFrame * p_frame;
+ int got_p_frame;
+};
+
+/*------------------------------------------------------------------------*/
+
+/**
+ * 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
+*/
+extern int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx);
+
+
+} // 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..03a39cabb5
--- /dev/null
+++ b/image/codecs/indeo/mem.cpp
@@ -0,0 +1,157 @@
+/* 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 ff_reverse[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,
+};
+
+/*------------------------------------------------------------------------*/
+
+/**
+ * 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 av_size_mult(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 *av_malloc(size_t size) {
+ return malloc(size);
+}
+
+void *av_mallocz(size_t size) {
+ void *ptr = av_malloc(size);
+ if (ptr)
+ memset(ptr, 0, size);
+
+ return ptr;
+}
+
+void *av_malloc_array(size_t nmemb, size_t size) {
+ if (!size || nmemb >= INT_MAX / size)
+ return nullptr;
+ return malloc(nmemb * size);
+}
+
+void *av_mallocz_array(size_t nmemb, size_t size) {
+ if (!size || nmemb >= INT_MAX / size)
+ return NULL;
+
+ return av_mallocz(nmemb * size);
+}
+
+void av_free(void *ptr) {
+ free(ptr);
+}
+
+void av_freep(void *arg) {
+ void **ptr = (void **)arg;
+ free(*ptr);
+ *ptr = nullptr;
+}
+
+static void *av_realloc(void *ptr, size_t size) {
+ return realloc(ptr, size + !size);
+}
+
+void *av_realloc_f(void *ptr, size_t nelem, size_t elsize) {
+ size_t size;
+ void *r;
+
+ if (av_size_mult(elsize, nelem, &size)) {
+ av_free(ptr);
+ return nullptr;
+ }
+ r = av_realloc(ptr, size);
+ if (!r)
+ av_free(ptr);
+
+ return r;
+}
+
+
+/**
+ * Swap the order of the bytes in the passed value
+ */
+uint32 bitswap_32(uint32 x) {
+ return (uint32)ff_reverse[x & 0xFF] << 24 |
+ (uint32)ff_reverse[(x >> 8) & 0xFF] << 16 |
+ (uint32)ff_reverse[(x >> 16) & 0xFF] << 8 |
+ (uint32)ff_reverse[x >> 24];
+}
+
+/**
+ * Reverse "nbits" bits of the value "val" and return the result
+ * in the least significant bits.
+ */
+uint16 inv_bits(uint16 val, int nbits) {
+ uint16 res;
+
+ if (nbits <= 8) {
+ res = ff_reverse[val] >> (8 - nbits);
+ } else
+ res = ((ff_reverse[val & 0xFF] << 8) +
+ (ff_reverse[val >> 8])) >> (16 - nbits);
+
+ return res;
+}
+
+} // 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..4f9ebf016d
--- /dev/null
+++ b/image/codecs/indeo/mem.h
@@ -0,0 +1,145 @@
+/* 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 FFSWAP(type,a,b) do{type SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0)
+
+/**
+ * Allocate a memory block with alignment suitable for all memory accesses
+ * (including vectors if available on the CPU).
+ *
+ * @param size Size in bytes for the memory block to be allocated
+ * @return Pointer to the allocated block, or `NULL` if the block cannot
+ * be allocated
+ * @see av_mallocz()
+ */
+extern void *av_malloc(size_t size);
+
+/**
+ * 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 *av_mallocz(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 *av_malloc_array(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 *av_mallocz_array(size_t nmemb, size_t size);
+
+/**
+ * Free a memory block which has been allocated with a function of av_malloc()
+ * or av_realloc() family.
+ *
+ * @param ptr Pointer to the memory block which should be freed.
+ *
+ * @note `ptr = NULL` is explicitly allowed.
+ * @note It is recommended that you use av_freep() instead, to prevent leaving
+ * behind dangling pointers.
+ * @see av_freep()
+ */
+extern void av_free(void *ptr);
+
+/**
+ * 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 av_freep(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 *av_realloc_f(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 inv_bits(uint16 val, int nbits);
+
+/**
+ * Swap the order of the bytes in the passed value
+ */
+extern uint32 bitswap_32(uint32 x);
+
+} // 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..441596585e
--- /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) FFSWAP(type, *start, *mid);\
+ else FFSWAP(type, *start, *end);\
+ }else{\
+ if(cmp(start, mid) > 0) FFSWAP(type, *start, *mid);\
+ else checksort= 1;\
+ }\
+ if(cmp(mid, end) > 0){ \
+ FFSWAP(type, *mid, *end);\
+ checksort=0;\
+ }\
+ if(start == end-2) break;\
+ FFSWAP(type, 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){\
+ FFSWAP(type, *left, *right);\
+ left++;\
+ right--;\
+ }\
+ }\
+ FFSWAP(type, 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)\
+ FFSWAP(type, *start, *end);\
+ break;\
+ }\
+ }\
+ }\
+} while (0)
+
+/**
+ * VLC decoding
+ */
+#define GET_DATA(v, table, i, wrap, size) \
+{ \
+ const uint8 *ptr = (const uint8 *)table + i * wrap; \
+ switch(size) { \
+ case 1: \
+ v = *(const uint8 *)ptr; \
+ break; \
+ case 2: \
+ v = *(const uint16 *)ptr; \
+ break; \
+ default: \
+ v = *(const uint32 *)ptr; \
+ break; \
+ } \
+}
+
+/*------------------------------------------------------------------------*/
+
+VLC::VLC() : bits(0), table_size(0), table_allocated(0), table(nullptr) {
+}
+
+int VLC::init_vlc(int nb_bits, int nb_codes, const void *bits, int bits_wrap, int bits_size,
+ const void *codes, int codes_wrap, int codes_size, int flags) {
+ return init_vlc(nb_bits, nb_codes, bits, bits_wrap, bits_size, codes, codes_wrap,
+ codes_size, nullptr, 0, 0, flags);
+}
+
+int VLC::init_vlc(int nb_bits, int nb_codes, const void *p_bits, int bits_wrap,
+ int bits_size, const void *codes, int codes_wrap, int codes_size,
+ const void *symbols, int symbols_wrap, int symbols_size, 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 = nb_bits;
+ if (flags & INIT_VLC_USE_NEW_STATIC) {
+ assert((nb_codes + 1) <= FF_ARRAY_ELEMS(localbuf));
+ buf = localbuf;
+ localvlc = *this;
+ vlc = &localvlc;
+ vlc->table_size = 0;
+ } else {
+ vlc->table = NULL;
+ vlc->table_allocated = 0;
+ vlc->table_size = 0;
+
+ buf = (VLCcode *)av_malloc_array((nb_codes + 1), sizeof(VLCcode));
+ assert(buf);
+ }
+
+ assert(symbols_size <= 2 || !symbols);
+ j = 0;
+#define COPY(condition)\
+ for (i = 0; i < nb_codes; i++) { \
+ GET_DATA(buf[j].bits, p_bits, i, bits_wrap, bits_size); \
+ if (!(condition)) \
+ continue; \
+ if (buf[j].bits > 3*nb_bits || 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; \
+ } \
+ GET_DATA(buf[j].code, codes, i, codes_wrap, codes_size); \
+ 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 = bitswap_32(buf[j].code); \
+ else \
+ buf[j].code <<= 32 - buf[j].bits; \
+ if (symbols) \
+ GET_DATA(buf[j].symbol, symbols, i, symbols_wrap, symbols_size) \
+ else \
+ buf[j].symbol = i; \
+ j++; \
+ }
+ COPY(buf[j].bits > nb_bits);
+
+ // qsort is the slowest part of init_vlc, and could probably be improved or avoided
+ AV_QSORT(buf, j, VLCcode, compare_vlcspec);
+ COPY(buf[j].bits && buf[j].bits <= nb_bits);
+ nb_codes = j;
+
+ ret = vlc->build_table(nb_bits, nb_codes, buf, flags);
+
+ if (flags & INIT_VLC_USE_NEW_STATIC) {
+ if (vlc->table_size != vlc->table_allocated)
+ warning("needed %d had %d", table_size, table_allocated);
+
+ assert(ret >= 0);
+ *this = *vlc;
+ } else {
+ free(buf);
+ if (ret < 0) {
+ av_freep(&vlc->table);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+void VLC::ff_free_vlc() {
+ free(table);
+}
+
+int VLC::compare_vlcspec(const void *a, const void *b) {
+ const VLCcode *sa = (VLCcode *)a, *sb = (VLCcode *)b;
+ return (sa->code >> 1) - (sb->code >> 1);
+}
+
+int VLC::build_table(int table_nb_bits, int nb_codes,
+ VLCcode *codes, int flags) {
+ VLC *vlc = this;
+ int table_size, table_index, index, code_prefix, symbol, subtable_bits;
+ int i, j, k, n, nb, inc;
+ uint32 code;
+ // the double volatile is needed to prevent an internal compiler error in gcc 4.2
+ volatile VLC_TYPE(*volatile table)[2];
+
+
+ table_size = 1 << table_nb_bits;
+ if (table_nb_bits > 30)
+ return -1;
+ table_index = alloc_table(table_size, flags & INIT_VLC_USE_NEW_STATIC);
+ warning("new table index=%d size=%d", table_index, table_size);
+ if (table_index < 0)
+ return table_index;
+ table = (volatile VLC_TYPE(*)[2])&vlc->table[table_index];
+
+ /* first pass: map codes and compute auxiliary table sizes */
+ for (i = 0; i < nb_codes; 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 <= table_nb_bits) {
+ /* no need to add another table */
+ j = code >> (32 - table_nb_bits);
+ nb = 1 << (table_nb_bits - n);
+ inc = 1;
+ if (flags & INIT_VLC_LE) {
+ j = bitswap_32(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 -= table_nb_bits;
+ code_prefix = code >> (32 - table_nb_bits);
+ subtable_bits = n;
+ codes[i].bits = n;
+ codes[i].code = code << table_nb_bits;
+ for (k = i + 1; k < nb_codes; k++) {
+ n = codes[k].bits - table_nb_bits;
+ if (n <= 0)
+ break;
+ code = codes[k].code;
+ if (code >> (32 - table_nb_bits) != code_prefix)
+ break;
+ codes[k].bits = n;
+ codes[k].code = code << table_nb_bits;
+ subtable_bits = MAX(subtable_bits, n);
+ }
+ subtable_bits = MIN(subtable_bits, table_nb_bits);
+ j = (flags & INIT_VLC_LE) ? bitswap_32(code_prefix) >> (32 - table_nb_bits) : code_prefix;
+ table[j][1] = -subtable_bits;
+ warning("%4x: n=%d (subtable)", j, codes[i].bits + table_nb_bits);
+ index = vlc->build_table(subtable_bits, k - i, codes + i, flags);
+ if (index < 0)
+ return index;
+ /* note: realloc has been done, so reload tables */
+ table = (volatile VLC_TYPE(*)[2])&vlc->table[table_index];
+ table[j][0] = index; //code
+ i = k - 1;
+ }
+ }
+
+ for (i = 0; i < table_size; i++) {
+ if (table[i][1] == 0) //bits
+ table[i][0] = -1; //codes
+ }
+
+ return table_index;
+}
+
+int VLC::alloc_table(int size, int use_static) {
+ VLC *vlc = this;
+ int index = vlc->table_size;
+
+ vlc->table_size += size;
+ if (vlc->table_size > vlc->table_allocated) {
+ // cannot do anything, init_vlc() is used with too little memory
+ assert(!use_static);
+
+ vlc->table_allocated += (1 << vlc->bits);
+ vlc->table = (int16(*)[2])av_realloc_f(vlc->table, vlc->table_allocated, sizeof(VLC_TYPE) * 2);
+ if (!vlc->table) {
+ vlc->table_allocated = 0;
+ vlc->table_size = 0;
+ return -2;
+ }
+
+ memset(vlc->table + vlc->table_allocated - (1 << vlc->bits), 0, sizeof(VLC_TYPE) * 2 << vlc->bits);
+ }
+ return index;
+}
+
+} // 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..682be66e4a
--- /dev/null
+++ b/image/codecs/indeo/vlc.h
@@ -0,0 +1,138 @@
+/* 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
+#define INIT_VLC_LE 2
+#define 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 compare_vlcspec(const void *a, const void *b);
+public:
+ int bits;
+ VLC_TYPE (*table)[2]; ///< code, bits
+ int table_size, table_allocated;
+
+ VLC();
+ ~VLC() { ff_free_vlc(); }
+
+
+ /* Build VLC decoding tables suitable for use with get_vlc().
+
+ 'nb_bits' sets the decoding table size (2^nb_bits) 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.
+
+ 'nb_codes' : 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.
+
+ 'use_static' should be set to 1 for tables, which should be freed
+ with av_free_static(), 0 if ff_free_vlc() will be used.
+ */
+ int init_vlc(int nb_bits, int nb_codes, const void *bits, int bits_wrap,
+ int bits_size, const void *codes, int codes_wrap, int codes_size,
+ const void *symbols, int symbols_wrap, int symbols_size, int flags);
+
+ int init_vlc(int nb_bits, int nb_codes, const void *bits, int bits_wrap, int bits_size,
+ const void *codes, int codes_wrap, int codes_size, int flags);
+
+ /**
+ * Free VLC data
+ */
+ void ff_free_vlc();
+
+
+ /**
+ * Build VLC decoding tables suitable for use with get_vlc().
+ *
+ * @param table_nb_bits max length of vlc codes to store directly in this table
+ * (Longer codes are delegated to subtables.)
+ *
+ * @param nb_codes 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 build_table(int table_nb_bits, int nb_codes,
+ VLCcode *codes, int flags);
+
+ int alloc_table(int size, int use_static);
+};
+
+
+/**
+ * Reverse "nbits" bits of the value "val" and return the result
+ * in the least significant bits.
+ */
+extern uint16 inv_bits(uint16 val, int nbits);
+
+/**
+ * Swap the order of the bytes in the passed value
+ */
+extern uint32 bitswap_32(uint32 x);
+
+} // End of namespace Indeo
+} // End of namespace Image
+
+#endif
diff --git a/image/codecs/indeo4.cpp b/image/codecs/indeo4.cpp
index 465e3adc49..bce9b5ad78 100644
--- a/image/codecs/indeo4.cpp
+++ b/image/codecs/indeo4.cpp
@@ -24,7 +24,7 @@
/* Intel Indeo 4 decompressor, derived from ffmpeg.
*
- * Original copyright note: * Intel Indeo 3 (IV31, IV32, etc.) video decoder for ffmpeg
+ * Original copyright note: * Intel Indeo 3 (IV41, IV42, etc.) video decoder for ffmpeg
* written, produced, and directed by Alan Smithee
*/
@@ -33,19 +33,22 @@
#include "common/stream.h"
#include "common/textconsole.h"
#include "common/util.h"
-
#include "graphics/yuv_to_rgb.h"
-
#include "image/codecs/indeo4.h"
-#include "image/codecs/indeo/get_bits.h"
namespace Image {
+#define IVI4_PIC_SIZE_ESC 7
+
Indeo4Decoder::Indeo4Decoder(uint16 width, uint16 height) {
_pixelFormat = g_system->getScreenFormat();
_surface = new Graphics::ManagedSurface();
_surface->create(width, height, _pixelFormat);
-
+ _ctx.gb = nullptr;
+ _ctx.pic_conf.pic_width = _ctx.pic_conf.pic_height = 0;
+ _ctx.is_indeo4 = true;
+ _ctx.show_indeo4_info = false;
+ _ctx.b_ref_buf = 3; // buffer 2 is used for scalability mode
}
Indeo4Decoder::~Indeo4Decoder() {
@@ -72,10 +75,191 @@ bool Indeo4Decoder::isIndeo4(Common::SeekableReadStream &stream) {
const Graphics::Surface *Indeo4Decoder::decodeFrame(Common::SeekableReadStream &stream) {
// Not Indeo 4? Fail
if (!isIndeo4(stream))
- return 0;
+ return nullptr;
+
+ // Set up the GetBits instance for reading the stream
+ _ctx.gb = new GetBits(stream);
+
+ // Decode the header
+ int err = decodePictureHeader();
+
+ delete _ctx.gb;
+ _ctx.gb = nullptr;
// TODO
- return nullptr;
+ err = -1;
+ return (err < 0) ? nullptr : &_surface->rawSurface();
}
+int Indeo4Decoder::decodePictureHeader() {
+ int pic_size_indx, i, p;
+ IVIPicConfig pic_conf;
+
+ if (_ctx.gb->getBits(18) != 0x3FFF8) {
+ warning("Invalid picture start code!");
+ return -1;
+ }
+
+ _ctx.prev_frame_type = _ctx.frame_type;
+ _ctx.frame_type = _ctx.gb->getBits(3);
+ if (_ctx.frame_type == 7) {
+ warning("Invalid frame type: %d", _ctx.frame_type);
+ return -1;
+ }
+
+ if (_ctx.frame_type == IVI4_FRAMETYPE_BIDIR)
+ _ctx.has_b_frames = 1;
+
+ _ctx.has_transp = _ctx.gb->getBits1();
+
+ // unknown bit: Mac decoder ignores this bit, XANIM returns error
+ if (_ctx.gb->getBits1()) {
+ warning("Sync bit is set!");
+ return -1;
+ }
+
+ _ctx.data_size = _ctx.gb->getBits1() ? _ctx.gb->getBits(24) : 0;
+
+ // null frames don't contain anything else so we just return
+ if (_ctx.frame_type >= IVI4_FRAMETYPE_NULL_FIRST) {
+ warning("Null frame encountered!");
+ return 0;
+ }
+
+ // Check key lock status. If enabled - ignore lock word.
+ // Usually we have to prompt the user for the password, but
+ // we don't do that because Indeo 4 videos can be decoded anyway
+ if (_ctx.gb->getBits1()) {
+ _ctx.gb->skipBitsLong(32);
+ warning("Password-protected clip!");
+ }
+
+ pic_size_indx = _ctx.gb->getBits(3);
+ if (pic_size_indx == IVI4_PIC_SIZE_ESC) {
+ pic_conf.pic_height = _ctx.gb->getBits(16);
+ pic_conf.pic_width = _ctx.gb->getBits(16);
+ } else {
+ pic_conf.pic_height = _ivi4_common_pic_sizes[pic_size_indx * 2 + 1];
+ pic_conf.pic_width = _ivi4_common_pic_sizes[pic_size_indx * 2];
+ }
+
+ // Decode tile dimensions.
+ _ctx.uses_tiling = _ctx.gb->getBits1();
+ if (_ctx.uses_tiling) {
+ pic_conf.tile_height = scaleTileSize(pic_conf.pic_height, _ctx.gb->getBits(4));
+ pic_conf.tile_width = scaleTileSize(pic_conf.pic_width, _ctx.gb->getBits(4));
+ } else {
+ pic_conf.tile_height = pic_conf.pic_height;
+ pic_conf.tile_width = pic_conf.pic_width;
+ }
+
+ // Decode chroma subsampling. We support only 4:4 aka YVU9.
+ if (_ctx.gb->getBits(2)) {
+ warning("Only YVU9 picture format is supported!");
+ return -1;
+ }
+ pic_conf.chroma_height = (pic_conf.pic_height + 3) >> 2;
+ pic_conf.chroma_width = (pic_conf.pic_width + 3) >> 2;
+
+ // decode subdivision of the planes
+ pic_conf.luma_bands = decodePlaneSubdivision();
+ pic_conf.chroma_bands = 0;
+ if (pic_conf.luma_bands)
+ pic_conf.chroma_bands = decodePlaneSubdivision();
+ _ctx.is_scalable = pic_conf.luma_bands != 1 || pic_conf.chroma_bands != 1;
+ if (_ctx.is_scalable && (pic_conf.luma_bands != 4 || pic_conf.chroma_bands != 1)) {
+ warning("Scalability: unsupported subdivision! Luma bands: %d, chroma bands: %d",
+ pic_conf.luma_bands, pic_conf.chroma_bands);
+ return -1;
+ }
+
+ // check if picture layout was changed and reallocate buffers
+ if (pic_conf.ivi_pic_config_cmp(_ctx.pic_conf)) {
+ if (IVIPlaneDesc::ff_ivi_init_planes(_ctx.planes, &pic_conf, 1)) {
+ warning("Couldn't reallocate color planes!");
+ _ctx.pic_conf.luma_bands = 0;
+ return -2;
+ }
+
+ _ctx.pic_conf = pic_conf;
+
+ // set default macroblock/block dimensions
+ for (p = 0; p <= 2; p++) {
+ for (i = 0; i < (!p ? pic_conf.luma_bands : pic_conf.chroma_bands); i++) {
+ _ctx.planes[p].bands[i].mb_size = !p ? (!_ctx.is_scalable ? 16 : 8) : 4;
+ _ctx.planes[p].bands[i].blk_size = !p ? 8 : 4;
+ }
+ }
+
+ if (IVIPlaneDesc::ff_ivi_init_tiles(_ctx.planes, _ctx.pic_conf.tile_width,
+ _ctx.pic_conf.tile_height)) {
+ warning("Couldn't reallocate internal structures!");
+ return -2;
+ }
+ }
+
+ _ctx.frame_num = _ctx.gb->getBits1() ? _ctx.gb->getBits(20) : 0;
+
+ // skip decTimeEst field if present
+ if (_ctx.gb->getBits1())
+ _ctx.gb->skipBits(8);
+
+ // decode macroblock and block huffman codebooks
+ if (_ctx.mb_vlc.ff_ivi_dec_huff_desc(_ctx.gb, _ctx.gb->getBits1(), IVI_MB_HUFF) ||
+ _ctx.blk_vlc.ff_ivi_dec_huff_desc(_ctx.gb, _ctx.gb->getBits1(), IVI_BLK_HUFF))
+ return -1;
+
+ _ctx.rvmap_sel = _ctx.gb->getBits1() ? _ctx.gb->getBits(3) : 8;
+
+ _ctx.in_imf = _ctx.gb->getBits1();
+ _ctx.in_q = _ctx.gb->getBits1();
+
+ _ctx.pic_glob_quant = _ctx.gb->getBits(5);
+
+ // TODO: ignore this parameter if unused
+ _ctx.unknown1 = _ctx.gb->getBits1() ? _ctx.gb->getBits(3) : 0;
+
+ _ctx.checksum = _ctx.gb->getBits1() ? _ctx.gb->getBits(16) : 0;
+
+ // skip picture header extension if any
+ while (_ctx.gb->getBits1()) {
+ warning("Pic hdr extension encountered!");
+ _ctx.gb->skipBits(8);
+ }
+
+ if (_ctx.gb->getBits1()) {
+ warning("Bad blocks bits encountered!");
+ }
+
+ _ctx.gb->alignGetBits();
+
+ return 0;
+}
+
+int Indeo4Decoder::scaleTileSize(int def_size, int size_factor) {
+ return size_factor == 15 ? def_size : (size_factor + 1) << 5;
+}
+
+int Indeo4Decoder::decodePlaneSubdivision() {
+ int i;
+
+ switch (_ctx.gb->getBits(2)) {
+ case 3:
+ return 1;
+ case 2:
+ for (i = 0; i < 4; i++)
+ if (_ctx.gb->getBits(2) != 3)
+ return 0;
+ return 4;
+ default:
+ return 0;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+const uint Indeo4Decoder::_ivi4_common_pic_sizes[14] = {
+ 640, 480, 320, 240, 160, 120, 704, 480, 352, 240, 352, 288, 176, 144
+};
+
} // End of namespace Image
diff --git a/image/codecs/indeo4.h b/image/codecs/indeo4.h
index 44007e08b8..838b0c3aef 100644
--- a/image/codecs/indeo4.h
+++ b/image/codecs/indeo4.h
@@ -21,6 +21,7 @@
*/
#include "common/scummsys.h"
+#include "image/codecs/indeo/get_bits.h"
/* Intel Indeo 4 decompressor, derived from ffmpeg.
*
@@ -33,10 +34,14 @@
#define IMAGE_CODECS_INDEO4_H
#include "image/codecs/codec.h"
+#include "image/codecs/indeo/get_bits.h"
+#include "image/codecs/indeo/indeo.h"
#include "graphics/managed_surface.h"
namespace Image {
+using namespace Indeo;
+
/**
* Intel Indeo 4 decoder.
*
@@ -57,6 +62,33 @@ public:
private:
Graphics::PixelFormat _pixelFormat;
Graphics::ManagedSurface *_surface;
+ IVI45DecContext _ctx;
+
+ /**
+ * Decode the Indeo 4 picture header.
+ * @returns 0 = Ok, negative number = error
+ */
+ int decodePictureHeader();
+
+ int scaleTileSize(int def_size, int size_factor);
+
+ /**
+ * Decode subdivision of a plane.
+ * This is a simplified version that checks for two supported subdivisions:
+ * - 1 wavelet band per plane, size factor 1:1, code pattern: 3
+ * - 4 wavelet bands per plane, size factor 1:4, code pattern: 2,3,3,3,3
+ * Anything else is either unsupported or corrupt.
+ *
+ * @param[in,out] gb the GetBit context
+ * @return number of wavelet bands or 0 on error
+ */
+ int decodePlaneSubdivision();
+
+private:
+ /**
+ * Standard picture dimensions
+ */
+ static const uint _ivi4_common_pic_sizes[14];
};
} // End of namespace Image
diff --git a/image/module.mk b/image/module.mk
index af4284dcdb..6d55b17240 100644
--- a/image/module.mk
+++ b/image/module.mk
@@ -23,7 +23,10 @@ MODULE_OBJS := \
codecs/smc.o \
codecs/svq1.o \
codecs/truemotion1.o \
- codecs/indeo/get_bits.o
+ codecs/indeo/get_bits.o \
+ codecs/indeo/indeo.o \
+ codecs/indeo/mem.o \
+ codecs/indeo/vlc.o
ifdef USE_MPEG2
MODULE_OBJS += \