aboutsummaryrefslogtreecommitdiff
path: root/image
diff options
context:
space:
mode:
authorPaul Gilbert2016-09-06 22:13:56 -0400
committerPaul Gilbert2016-09-10 10:08:14 -0400
commit9e774af4d91cb3adddfb6acc2024653620e725db (patch)
tree44eadc8766ce0f8d36e5409e323648ea39e61f54 /image
parentc165826316a71b378e3493a4a5fb6a6e1740bbab (diff)
downloadscummvm-rg350-9e774af4d91cb3adddfb6acc2024653620e725db.tar.gz
scummvm-rg350-9e774af4d91cb3adddfb6acc2024653620e725db.tar.bz2
scummvm-rg350-9e774af4d91cb3adddfb6acc2024653620e725db.zip
IMAGE: Further implementation of Indeo image decoding
Diffstat (limited to 'image')
-rw-r--r--image/codecs/indeo/get_bits.cpp2
-rw-r--r--image/codecs/indeo/get_bits.h2
-rw-r--r--image/codecs/indeo/indeo.cpp883
-rw-r--r--image/codecs/indeo/indeo.h190
-rw-r--r--image/codecs/indeo/indeo_dsp.cpp639
-rw-r--r--image/codecs/indeo/indeo_dsp.h338
-rw-r--r--image/codecs/indeo/mem.cpp24
-rw-r--r--image/codecs/indeo/mem.h29
-rw-r--r--image/codecs/indeo4.cpp694
-rw-r--r--image/codecs/indeo4.h55
-rw-r--r--image/module.mk1
11 files changed, 2835 insertions, 22 deletions
diff --git a/image/codecs/indeo/get_bits.cpp b/image/codecs/indeo/get_bits.cpp
index 98cef7facd..fce773d8b4 100644
--- a/image/codecs/indeo/get_bits.cpp
+++ b/image/codecs/indeo/get_bits.cpp
@@ -438,7 +438,7 @@ const byte *GetBits::alignGetBits() {
* read the longest vlc code
* = (max_vlc_length + bits - 1) / bits
*/
-int GetBits::getVLC2(int (*table)[2], int bits, int maxDepth) {
+int GetBits::getVLC2(int16 (*table)[2], int bits, int maxDepth) {
int code;
OPEN_READER(re);
diff --git a/image/codecs/indeo/get_bits.h b/image/codecs/indeo/get_bits.h
index 313fe7e2da..f9f577c8bd 100644
--- a/image/codecs/indeo/get_bits.h
+++ b/image/codecs/indeo/get_bits.h
@@ -169,7 +169,7 @@ public:
* read the longest vlc code
* = (max_vlc_length + bits - 1) / bits
*/
- int getVLC2(int(*table)[2], int bits, int maxDepth);
+ int getVLC2(int16 (*table)[2], int bits, int maxDepth);
int decode012();
diff --git a/image/codecs/indeo/indeo.cpp b/image/codecs/indeo/indeo.cpp
index 820823b77e..e530c5737a 100644
--- a/image/codecs/indeo/indeo.cpp
+++ b/image/codecs/indeo/indeo.cpp
@@ -30,6 +30,7 @@
*/
#include "image/codecs/indeo/indeo.h"
+#include "image/codecs/indeo/indeo_dsp.h"
#include "image/codecs/indeo/mem.h"
#include "common/system.h"
#include "common/textconsole.h"
@@ -390,7 +391,6 @@ IndeoDecoderBase::IndeoDecoderBase(uint16 width, uint16 height) : Codec() {
_surface->create(width, height, _pixelFormat);
_ctx.gb = nullptr;
_ctx.pic_conf.pic_width = _ctx.pic_conf.pic_height = 0;
- _ctx.show_indeo4_info = false;
_ctx.b_ref_buf = 3; // buffer 2 is used for scalability mode
}
@@ -399,32 +399,893 @@ IndeoDecoderBase::~IndeoDecoderBase() {
}
int IndeoDecoderBase::decodeIndeoFrame() {
+ int result, p, b;
+ AVFrame frameData;
+ AVFrame *frame = &frameData;
+
// Decode the header
- int err = decodePictureHeader();
+ if (decodePictureHeader() < 0)
+ return -1;
- if (!err && _ctx.gop_invalid)
- err = -1;
+ if (_ctx.gop_invalid)
+ return -1;
- if (!err && _ctx.frame_type == IVI4_FRAMETYPE_NULL_LAST) {
+ if (_ctx.frame_type == IVI4_FRAMETYPE_NULL_LAST) {
// Returning the previous frame, so exit wth success
return 0;
}
- if (!err && _ctx.gop_flags & IVI5_IS_PROTECTED) {
+ if (_ctx.gop_flags & IVI5_IS_PROTECTED) {
warning("Password-protected clip");
- err = -1;
+ return -1;
}
- if (!err && !_ctx.planes[0].bands) {
+ if (!_ctx.planes[0].bands) {
warning("Color planes not initialized yet");
- err = -1;
+ return -1;
+ }
+
+ switch_buffers();
+
+ //{ START_TIMER;
+
+ if (is_nonnull_frame()) {
+ _ctx.buf_invalid[_ctx.dst_buf] = 1;
+ for (p = 0; p < 3; p++) {
+ for (b = 0; b < _ctx.planes[p].num_bands; 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.buf_invalid[_ctx.dst_buf] = 0;
+ } else {
+ if (_ctx.is_scalable)
+ return -1;
+
+ for (p = 0; p < 3; p++) {
+ if (!_ctx.planes[p].bands[0].buf)
+ return -1;
+ }
+ }
+ if (_ctx.buf_invalid[_ctx.dst_buf])
+ return -1;
+
+ //STOP_TIMER("decode_planes"); }
+
+ if (!is_nonnull_frame())
+ return 0;
+
+ result = ff_set_dimensions(_ctx.planes[0].width, _ctx.planes[0].height);
+ if (result < 0)
+ return result;
+
+ if ((result = ff_get_buffer(frame, 0)) < 0)
+ return result;
+
+ if (_ctx.is_scalable) {
+ if (_ctx.is_indeo4)
+ ff_ivi_recompose_haar(&_ctx.planes[0], frame->data[0], frame->linesize[0]);
+ else
+ ff_ivi_recompose53(&_ctx.planes[0], frame->data[0], frame->linesize[0]);
+ } else {
+ ivi_output_plane(&_ctx.planes[0], frame->data[0], frame->linesize[0]);
+ }
+
+ ivi_output_plane(&_ctx.planes[2], frame->data[1], frame->linesize[1]);
+ ivi_output_plane(&_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.is_indeo4 && _ctx.frame_type == IVI4_FRAMETYPE_INTRA) {
+ int left;
+
+ // skip version string
+ while (_ctx.gb->getBits(8)) {
+ if (_ctx.gb->getBitsLeft() < 8)
+ return -1;
+ }
+ left = _ctx.gb->getBitsCount() & 0x18;
+ _ctx.gb->skipBitsLong(64 - left);
+ if (_ctx.gb->getBitsLeft() > 18 &&
+ _ctx.gb->showBitsLong(21) == 0xBFFF8) { // syncheader + inter type
+ error("Indeo decoder: Mode not currently implemented in ScummVM");
+ }
+ }
+
+ return 0;
+}
+
+int IndeoDecoderBase::decode_band(IVIBandDesc *band) {
+ int result, i, t, idx1, idx2, pos;
+ IVITile * tile;
+
+ band->buf = band->bufs[_ctx.dst_buf];
+ if (!band->buf) {
+ warning("Band buffer points to no data!");
+ return -1;
+ }
+ if (_ctx.is_indeo4 && _ctx.frame_type == IVI4_FRAMETYPE_BIDIR) {
+ band->ref_buf = band->bufs[_ctx.b_ref_buf];
+ band->b_ref_buf = band->bufs[_ctx.ref_buf];
+ }
+ else {
+ band->ref_buf = band->bufs[_ctx.ref_buf];
+ band->b_ref_buf = 0;
+ }
+ band->data_ptr = _ctx.frame_data + (_ctx.gb->getBitsCount() >> 3);
+
+ result = decode_band_hdr(band);
+ if (result) {
+ warning("Error while decoding band header: %d",
+ result);
+ return result;
+ }
+
+ if (band->is_empty) {
+ warning("Empty band encountered!");
+ return -1;
+ }
+
+ band->rv_map = &_ctx.rvmap_tabs[band->rvmap_sel];
+
+ /* apply corrections to the selected rvmap table if present */
+ for (i = 0; i < band->num_corr; i++) {
+ idx1 = band->corr[i * 2];
+ idx2 = band->corr[i * 2 + 1];
+ FFSWAP(uint8, band->rv_map->runtab[idx1], band->rv_map->runtab[idx2]);
+ FFSWAP(int16, band->rv_map->valtab[idx1], band->rv_map->valtab[idx2]);
+ if (idx1 == band->rv_map->eob_sym || idx2 == band->rv_map->eob_sym)
+ band->rv_map->eob_sym ^= idx1 ^ idx2;
+ if (idx1 == band->rv_map->esc_sym || idx2 == band->rv_map->esc_sym)
+ band->rv_map->esc_sym ^= idx1 ^ idx2;
}
- // TODO
+ pos = _ctx.gb->getBitsCount();
+
+ for (t = 0; t < band->num_tiles; t++) {
+ tile = &band->tiles[t];
+
+ if (tile->mb_size != band->mb_size) {
+ warning("MB sizes mismatch: %d vs. %d",
+ band->mb_size, tile->mb_size);
+ return -1;
+ }
+ tile->is_empty = _ctx.gb->getBits1();
+ if (tile->is_empty) {
+ result = ivi_process_empty_tile(band, tile,
+ (_ctx.planes[0].bands[0].mb_size >> 3) - (band->mb_size >> 3));
+ if (result < 0)
+ break;
+ warning("Empty tile encountered!");
+ } else {
+ tile->data_size = ivi_dec_tile_data_size(_ctx.gb);
+ if (!tile->data_size) {
+ warning("Tile data size is zero!");
+ result = -1;
+ break;
+ }
+
+ result = decode_mb_info(band, tile);
+ if (result < 0)
+ break;
+
+ result = ivi_decode_blocks(_ctx.gb, band, tile);
+ if (result < 0) {
+ warning("Corrupted tile data encountered!");
+ break;
+ }
+
+ if ((((int)_ctx.gb->getBitsCount() - pos) >> 3) != tile->data_size) {
+ warning("Tile data_size mismatch!");
+ result = -1;
+ break;
+ }
+
+ pos += tile->data_size << 3; // skip to next tile
+ }
+ }
+
+ // restore the selected rvmap table by applying its corrections in
+ // reverse order
+ for (i = band->num_corr - 1; i >= 0; i--) {
+ idx1 = band->corr[i * 2];
+ idx2 = band->corr[i * 2 + 1];
+ FFSWAP(uint8, band->rv_map->runtab[idx1], band->rv_map->runtab[idx2]);
+ FFSWAP(int16, band->rv_map->valtab[idx1], band->rv_map->valtab[idx2]);
+ if (idx1 == band->rv_map->eob_sym || idx2 == band->rv_map->eob_sym)
+ band->rv_map->eob_sym ^= idx1 ^ idx2;
+ if (idx1 == band->rv_map->esc_sym || idx2 == band->rv_map->esc_sym)
+ band->rv_map->esc_sym ^= idx1 ^ idx2;
+ }
+
+ _ctx.gb->alignGetBits();
+
+ return result;
+}
+
+int IndeoDecoderBase::ff_set_dimensions(uint16 width, uint16 height) {
+ if (_surface->w != width || _surface->h != height)
+ _surface->create(width, height);
+
+ return 0;
+}
+
+int IndeoDecoderBase::ff_get_buffer(AVFrame *frame, int flags) {
+ frame->data[0] = (uint8 *)_surface->getBasePtr(0, 0);
+ return 0;
+}
- return err;
+void IndeoDecoderBase::ff_ivi_recompose_haar(const IVIPlaneDesc *plane,
+ uint8 *dst, const int dst_pitch) {
+ int x, y, indx, b0, b1, b2, b3, p0, p1, p2, p3;
+ const short * b0_ptr, *b1_ptr, *b2_ptr, *b3_ptr;
+ int32 pitch;
+
+ // all bands should have the same pitch
+ pitch = plane->bands[0].pitch;
+
+ // get pointers to the wavelet bands
+ b0_ptr = plane->bands[0].buf;
+ b1_ptr = plane->bands[1].buf;
+ b2_ptr = plane->bands[2].buf;
+ b3_ptr = 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 = b0_ptr[indx]; //should be: b0 = (num_bands > 0) ? b0_ptr[indx] : 0;
+ b1 = b1_ptr[indx]; //should be: b1 = (num_bands > 1) ? b1_ptr[indx] : 0;
+ b2 = b2_ptr[indx]; //should be: b2 = (num_bands > 2) ? b2_ptr[indx] : 0;
+ b3 = b3_ptr[indx]; //should be: b3 = (num_bands > 3) ? b3_ptr[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] = av_clip_uint8(p0 + 128);
+ dst[x + 1] = av_clip_uint8(p1 + 128);
+ dst[dst_pitch + x] = av_clip_uint8(p2 + 128);
+ dst[dst_pitch + x + 1] = av_clip_uint8(p3 + 128);
+ }// for x
+
+ dst += dst_pitch << 1;
+
+ b0_ptr += pitch;
+ b1_ptr += pitch;
+ b2_ptr += pitch;
+ b3_ptr += pitch;
+ }// for y
}
+
+void IndeoDecoderBase::ff_ivi_recompose53(const IVIPlaneDesc *plane,
+ uint8 *dst, const int dst_pitch) {
+ 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 * b0_ptr, *b1_ptr, *b2_ptr, *b3_ptr;
+ const int num_bands = 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
+ b0_ptr = plane->bands[0].buf;
+ b1_ptr = plane->bands[1].buf;
+ b2_ptr = plane->bands[2].buf;
+ b3_ptr = 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 (num_bands > 0) {
+ b0_1 = b0_ptr[0];
+ b0_2 = b0_ptr[pitch];
+ }
+
+ if (num_bands > 1) {
+ b1_1 = b1_ptr[back_pitch];
+ b1_2 = b1_ptr[0];
+ b1_3 = b1_1 - b1_2 * 6 + b1_ptr[pitch];
+ }
+
+ if (num_bands > 2) {
+ b2_2 = b2_ptr[0]; // b2[x, y ]
+ b2_3 = b2_2; // b2[x+1,y ] = b2[x,y]
+ b2_5 = b2_ptr[pitch]; // b2[x ,y+1]
+ b2_6 = b2_5; // b2[x+1,y+1] = b2[x,y+1]
+ }
+
+ if (num_bands > 3) {
+ b3_2 = b3_ptr[back_pitch]; // b3[x ,y-1]
+ b3_3 = b3_2; // b3[x+1,y-1] = b3[x ,y-1]
+ b3_5 = b3_ptr[0]; // b3[x ,y ]
+ b3_6 = b3_5; // b3[x+1,y ] = b3[x ,y ]
+ b3_8 = b3_2 - b3_5 * 6 + b3_ptr[pitch];
+ b3_9 = b3_8;
+ }
+
+ for (x = 0, indx = 0; x < plane->width; x += 2, indx++) {
+ if (x + 2 >= plane->width) {
+ b0_ptr--;
+ b1_ptr--;
+ b2_ptr--;
+ b3_ptr--;
+ }
+
+ // 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 (num_bands > 0) {
+ tmp0 = b0_1;
+ tmp2 = b0_2;
+ b0_1 = b0_ptr[indx + 1];
+ b0_2 = b0_ptr[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 (num_bands > 1) {
+ tmp0 = b1_2;
+ tmp1 = b1_1;
+ b1_2 = b1_ptr[indx + 1];
+ b1_1 = b1_ptr[back_pitch + indx + 1];
+
+ tmp2 = tmp1 - tmp0 * 6 + b1_3;
+ b1_3 = b1_1 - b1_2 * 6 + b1_ptr[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 (num_bands > 2) {
+ b2_3 = b2_ptr[indx + 1];
+ b2_6 = b2_ptr[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 (num_bands > 3) {
+ b3_6 = b3_ptr[indx + 1]; // b3[x+1,y ]
+ b3_3 = b3_ptr[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 + b3_ptr[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] = av_clip_uint8((p0 >> 6) + 128);
+ dst[x + 1] = av_clip_uint8((p1 >> 6) + 128);
+ dst[dst_pitch + x] = av_clip_uint8((p2 >> 6) + 128);
+ dst[dst_pitch + x + 1] = av_clip_uint8((p3 >> 6) + 128);
+ }// for x
+
+ dst += dst_pitch << 1;
+
+ back_pitch = -pitch;
+
+ b0_ptr += pitch + 1;
+ b1_ptr += pitch + 1;
+ b2_ptr += pitch + 1;
+ b3_ptr += pitch + 1;
+ }
+}
+
+void IndeoDecoderBase::ivi_output_plane(IVIPlaneDesc *plane, uint8 *dst, int dst_pitch) {
+ 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] = av_clip_uint8(src[x] + 128);
+ src += pitch;
+ dst += dst_pitch;
+ }
+}
+
+int IndeoDecoderBase::ivi_process_empty_tile(IVIBandDesc *band,
+ IVITile *tile, int32 mv_scale) {
+ int x, y, need_mc, mbn, blk, num_blocks, mv_x, mv_y, mc_type;
+ int offs, mb_offset, row_offset, ret;
+ IVIMbInfo *mb, *ref_mb;
+ const int16 *src;
+ int16 *dst;
+ ivi_mc_func mc_no_delta_func;
+
+ if (tile->num_MBs != IVI_MBs_PER_TILE(tile->width, tile->height, band->mb_size)) {
+ warning("Allocated tile size %d mismatches "
+ "parameters %d in ivi_process_empty_tile()",
+ tile->num_MBs, IVI_MBs_PER_TILE(tile->width, tile->height, band->mb_size));
+ return -1;
+ }
+
+ offs = tile->ypos * band->pitch + tile->xpos;
+ mb = tile->mbs;
+ ref_mb = tile->ref_mbs;
+ row_offset = band->mb_size * band->pitch;
+ need_mc = 0; /* reset the mc tracking flag */
+
+ for (y = tile->ypos; y < (tile->ypos + tile->height); y += band->mb_size) {
+ mb_offset = offs;
+
+ for (x = tile->xpos; x < (tile->xpos + tile->width); x += band->mb_size) {
+ mb->xpos = x;
+ mb->ypos = y;
+ mb->buf_offs = mb_offset;
+
+ mb->type = 1; /* set the macroblocks type = INTER */
+ mb->cbp = 0; /* all blocks are empty */
+
+ if (!band->qdelta_present && !band->plane && !band->band_num) {
+ mb->q_delta = band->glob_quant;
+ mb->mv_x = 0;
+ mb->mv_y = 0;
+ }
+
+ if (band->inherit_qdelta && ref_mb)
+ mb->q_delta = ref_mb->q_delta;
+
+ if (band->inherit_mv && ref_mb) {
+ /* motion vector inheritance */
+ if (mv_scale) {
+ mb->mv_x = ivi_scale_mv(ref_mb->mv_x, mv_scale);
+ mb->mv_y = ivi_scale_mv(ref_mb->mv_y, mv_scale);
+ } else {
+ mb->mv_x = ref_mb->mv_x;
+ mb->mv_y = ref_mb->mv_y;
+ }
+ need_mc |= mb->mv_x || mb->mv_y; /* tracking non-zero motion vectors */
+ {
+ int dmv_x, dmv_y, cx, cy;
+
+ dmv_x = mb->mv_x >> band->is_halfpel;
+ dmv_y = mb->mv_y >> band->is_halfpel;
+ cx = mb->mv_x & band->is_halfpel;
+ cy = mb->mv_y & band->is_halfpel;
+
+ if (mb->xpos + dmv_x < 0
+ || mb->xpos + dmv_x + band->mb_size + cx > band->pitch
+ || mb->ypos + dmv_y < 0
+ || mb->ypos + dmv_y + band->mb_size + cy > band->aheight) {
+ warning("MV out of bounds");
+ return -1;
+ }
+ }
+ }
+
+ mb++;
+ if (ref_mb)
+ ref_mb++;
+ mb_offset += band->mb_size;
+ } // for x
+ offs += row_offset;
+ } // for y
+
+ if (band->inherit_mv && need_mc) { // apply motion compensation if there is at least one non-zero motion vector
+ num_blocks = (band->mb_size != band->blk_size) ? 4 : 1; // number of blocks per mb
+ mc_no_delta_func = (band->blk_size == 8) ? IndeoDSP::ff_ivi_mc_8x8_no_delta
+ : IndeoDSP::ff_ivi_mc_4x4_no_delta;
+
+ for (mbn = 0, mb = tile->mbs; mbn < tile->num_MBs; mb++, mbn++) {
+ mv_x = mb->mv_x;
+ mv_y = mb->mv_y;
+ if (!band->is_halfpel) {
+ mc_type = 0; // we have only fullpel vectors
+ } else {
+ mc_type = ((mv_y & 1) << 1) | (mv_x & 1);
+ mv_x >>= 1;
+ mv_y >>= 1; // convert halfpel vectors into fullpel ones
+ }
+
+ for (blk = 0; blk < num_blocks; blk++) {
+ // adjust block position in the buffer according with its number
+ offs = mb->buf_offs + band->blk_size * ((blk & 1) + !!(blk & 2) * band->pitch);
+ ret = ivi_mc(band, mc_no_delta_func, nullptr, offs,
+ mv_x, mv_y, 0, 0, mc_type, -1);
+ if (ret < 0)
+ return ret;
+ }
+ }
+ } else {
+ // copy data from the reference tile into the current one
+ src = band->ref_buf + 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::ivi_dec_tile_data_size(GetBits *gb) {
+ int len = 0;
+
+ if (gb->getBits1()) {
+ len = gb->getBits(8);
+ if (len == 255)
+ len = gb->getBitsLong(24);
+ }
+
+ // align the bitstream reader on the byte boundary
+ gb->alignGetBits();
+
+ return len;
+}
+
+int IndeoDecoderBase::ivi_decode_blocks(GetBits *gb, IVIBandDesc *band, IVITile *tile) {
+ int mbn, blk, num_blocks, blk_size, ret, is_intra;
+ int mc_type = 0, mc_type2 = -1;
+ int mv_x = 0, mv_y = 0, mv_x2 = 0, mv_y2 = 0;
+ int32 prev_dc;
+ uint32 cbp, quant, buf_offs;
+ IVIMbInfo *mb;
+ ivi_mc_func mc_with_delta_func, mc_no_delta_func;
+ ivi_mc_avg_func mc_avg_with_delta_func, mc_avg_no_delta_func;
+ const uint8 *scale_tab;
+
+ /* init intra prediction for the DC coefficient */
+ prev_dc = 0;
+ blk_size = band->blk_size;
+ /* number of blocks per mb */
+ num_blocks = (band->mb_size != blk_size) ? 4 : 1;
+ if (blk_size == 8) {
+ mc_with_delta_func = IndeoDSP::ff_ivi_mc_8x8_delta;
+ mc_no_delta_func = IndeoDSP::ff_ivi_mc_8x8_no_delta;
+ mc_avg_with_delta_func = IndeoDSP::ff_ivi_mc_avg_8x8_delta;
+ mc_avg_no_delta_func = IndeoDSP::ff_ivi_mc_avg_8x8_no_delta;
+ } else {
+ mc_with_delta_func = IndeoDSP::ff_ivi_mc_4x4_delta;
+ mc_no_delta_func = IndeoDSP::ff_ivi_mc_4x4_no_delta;
+ mc_avg_with_delta_func = IndeoDSP::ff_ivi_mc_avg_4x4_delta;
+ mc_avg_no_delta_func = IndeoDSP::ff_ivi_mc_avg_4x4_no_delta;
+ }
+
+ for (mbn = 0, mb = tile->mbs; mbn < tile->num_MBs; mb++, mbn++) {
+ is_intra = !mb->type;
+ cbp = mb->cbp;
+ buf_offs = mb->buf_offs;
+
+ quant = band->glob_quant + mb->q_delta;
+ if (_ctx.is_indeo4)
+ quant = av_clip_uintp2(quant, 5);
+ else
+ quant = av_clip((int)quant, 0, 23);
+
+ scale_tab = is_intra ? band->intra_scale : band->inter_scale;
+ if (scale_tab)
+ quant = scale_tab[quant];
+
+ if (!is_intra) {
+ mv_x = mb->mv_x;
+ mv_y = mb->mv_y;
+ mv_x2 = mb->b_mv_x;
+ mv_y2 = mb->b_mv_y;
+ if (band->is_halfpel) {
+ mc_type = ((mv_y & 1) << 1) | (mv_x & 1);
+ mc_type2 = ((mv_y2 & 1) << 1) | (mv_x2 & 1);
+ mv_x >>= 1;
+ mv_y >>= 1;
+ mv_x2 >>= 1;
+ mv_y2 >>= 1; /* convert halfpel vectors into fullpel ones */
+ }
+ if (mb->type == 2)
+ mc_type = -1;
+ if (mb->type != 2 && mb->type != 3)
+ mc_type2 = -1;
+ if (mb->type) {
+ int dmv_x, dmv_y, cx, cy;
+
+ dmv_x = mb->mv_x >> band->is_halfpel;
+ dmv_y = mb->mv_y >> band->is_halfpel;
+ cx = mb->mv_x & band->is_halfpel;
+ cy = mb->mv_y & band->is_halfpel;
+
+ if (mb->xpos + dmv_x < 0 ||
+ mb->xpos + dmv_x + band->mb_size + cx > band->pitch ||
+ mb->ypos + dmv_y < 0 ||
+ mb->ypos + dmv_y + band->mb_size + cy > band->aheight) {
+ return -1;
+ }
+ }
+ if (mb->type == 2 || mb->type == 3) {
+ int dmv_x, dmv_y, cx, cy;
+
+ dmv_x = mb->b_mv_x >> band->is_halfpel;
+ dmv_y = mb->b_mv_y >> band->is_halfpel;
+ cx = mb->b_mv_x & band->is_halfpel;
+ cy = mb->b_mv_y & band->is_halfpel;
+
+ if (mb->xpos + dmv_x < 0 ||
+ mb->xpos + dmv_x + band->mb_size + cx > band->pitch ||
+ mb->ypos + dmv_y < 0 ||
+ mb->ypos + dmv_y + band->mb_size + cy > band->aheight) {
+ return -1;
+ }
+ }
+ }
+
+ for (blk = 0; blk < num_blocks; blk++) {
+ // adjust block position in the buffer according to its number
+ if (blk & 1) {
+ buf_offs += blk_size;
+ } else if (blk == 2) {
+ buf_offs -= blk_size;
+ buf_offs += blk_size * band->pitch;
+ }
+
+ if (cbp & 1) { // block coded ?
+ ret = ivi_decode_coded_blocks(gb, band, mc_with_delta_func,
+ mc_avg_with_delta_func,
+ mv_x, mv_y, mv_x2, mv_y2,
+ &prev_dc, is_intra,
+ mc_type, mc_type2, quant,
+ buf_offs);
+ 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 (is_intra) {
+ ret = ivi_dc_transform(band, &prev_dc, buf_offs, blk_size);
+ if (ret < 0)
+ return ret;
+ } else {
+ ret = ivi_mc(band, mc_no_delta_func, mc_avg_no_delta_func,
+ buf_offs, mv_x, mv_y, mv_x2, mv_y2,
+ mc_type, mc_type2);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ cbp >>= 1;
+ }// for blk
+ }// for mbn
+
+ gb->alignGetBits();
+ return 0;
+}
+
+int IndeoDecoderBase::ivi_scale_mv(int mv, int mv_scale){
+ return (mv + (mv > 0) + (mv_scale - 1)) >> mv_scale;
+}
+
+int IndeoDecoderBase::ivi_mc(IVIBandDesc *band, ivi_mc_func mc, ivi_mc_avg_func mc_avg,
+ int offs, int mv_x, int mv_y, int mv_x2, int mv_y2,
+ int mc_type, int mc_type2){
+ int ref_offs = offs + mv_y * band->pitch + mv_x;
+ int buf_size = band->pitch * band->aheight;
+ int min_size = band->pitch * (band->blk_size - 1) + band->blk_size;
+ int ref_size = (mc_type > 1) * band->pitch + (mc_type & 1);
+
+ if (mc_type != -1) {
+ assert(offs >= 0 && ref_offs >= 0 && band->ref_buf);
+ assert(buf_size - min_size >= offs);
+ assert(buf_size - min_size - ref_size >= ref_offs);
+ }
+
+ if (mc_type2 == -1) {
+ mc(band->buf + offs, band->ref_buf + ref_offs, band->pitch, mc_type);
+ } else {
+ int ref_offs2 = offs + mv_y2 * band->pitch + mv_x2;
+ int ref_size2 = (mc_type2 > 1) * band->pitch + (mc_type2 & 1);
+ if (offs < 0 || ref_offs2 < 0 || !band->b_ref_buf)
+ return -1;
+ if (buf_size - min_size - ref_size2 < ref_offs2)
+ return -1;
+
+ if (mc_type == -1)
+ mc(band->buf + offs, band->b_ref_buf + ref_offs2,
+ band->pitch, mc_type2);
+ else
+ mc_avg(band->buf + offs, band->ref_buf + ref_offs,
+ band->b_ref_buf + ref_offs2, band->pitch,
+ mc_type, mc_type2);
+ }
+
+ return 0;
+}
+
+int IndeoDecoderBase::ivi_decode_coded_blocks(GetBits *gb, IVIBandDesc *band,
+ ivi_mc_func mc, ivi_mc_avg_func mc_avg, int mv_x, int mv_y,
+ int mv_x2, int mv_y2, int *prev_dc, int is_intra,
+ int mc_type, int mc_type2, uint32 quant, int offs) {
+ const uint16 *base_tab = is_intra ? band->intra_base : band->inter_base;
+ RVMapDesc *rvmap = band->rv_map;
+ uint8 col_flags[8];
+ int32 trvec[64];
+ uint32 sym = 0, lo, hi, q;
+ int pos, run, val;
+ int blk_size = band->blk_size;
+ int num_coeffs = blk_size * blk_size;
+ int col_mask = blk_size - 1;
+ int scan_pos = -1;
+ int min_size = band->pitch * (band->transform_size - 1) +
+ band->transform_size;
+ int buf_size = band->pitch * band->aheight - offs;
+
+ if (min_size > buf_size)
+ return -1;
+
+ if (!band->scan) {
+ warning("Scan pattern is not set.");
+ return -1;
+ }
+
+ // zero transform vector
+ memset(trvec, 0, num_coeffs * sizeof(trvec[0]));
+ // zero column flags
+ memset(col_flags, 0, sizeof(col_flags));
+ while (scan_pos <= num_coeffs) {
+ sym = gb->getVLC2(band->blk_vlc.tab->table,
+ IVI_VLC_BITS, 1);
+ if (sym == rvmap->eob_sym)
+ break; // End of block
+
+ // Escape - run/val explicitly coded using 3 vlc codes
+ if (sym == rvmap->esc_sym) {
+ run = gb->getVLC2(band->blk_vlc.tab->table, IVI_VLC_BITS, 1) + 1;
+ lo = gb->getVLC2(band->blk_vlc.tab->table, IVI_VLC_BITS, 1);
+ hi = gb->getVLC2(band->blk_vlc.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
+ scan_pos += run;
+ if (scan_pos >= num_coeffs || scan_pos < 0)
+ break;
+ pos = band->scan[scan_pos];
+
+ if (!val)
+ warning("Val = 0 encountered!");
+
+ q = (base_tab[pos] * quant) >> 9;
+ if (q > 1)
+ val = val * q + FFSIGN(val) * (((q ^ 1) - 1) >> 1);
+ trvec[pos] = val;
+ // track columns containing non-zero coeffs
+ col_flags[pos & col_mask] |= !!val;
+ }
+
+ if (scan_pos < 0 || scan_pos >= num_coeffs && sym != rvmap->eob_sym)
+ return -1; // corrupt block data
+
+ // undoing DC coeff prediction for intra-blocks
+ if (is_intra && band->is_2d_trans) {
+ *prev_dc += trvec[0];
+ trvec[0] = *prev_dc;
+ col_flags[0] |= !!*prev_dc;
+ }
+
+ if (band->transform_size > band->blk_size) {
+ warning("Too large transform");
+ return -1;
+ }
+
+ // apply inverse transform
+ band->inv_transform(trvec, band->buf + offs,
+ band->pitch, col_flags);
+
+ // apply motion compensation
+ if (!is_intra)
+ return ivi_mc(band, mc, mc_avg, offs, mv_x, mv_y, mv_x2, mv_y2,
+ mc_type, mc_type2);
+
+ return 0;
+}
+
+int IndeoDecoderBase::ivi_dc_transform(IVIBandDesc *band, int *prev_dc,
+ int buf_offs, int blk_size) {
+ int buf_size = band->pitch * band->aheight - buf_offs;
+ int min_size = (blk_size - 1) * band->pitch + blk_size;
+
+ if (min_size > buf_size)
+ return -1;
+
+ band->dc_transform(prev_dc, band->buf + buf_offs,
+ band->pitch, blk_size);
+
+ return 0;
+}
+
+
+/**
+ * Scan patterns shared between indeo4 and indeo5
+ */
+const uint8 IndeoDecoderBase::_ff_ivi_vertical_scan_8x8[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::_ff_ivi_horizontal_scan_8x8[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::_ff_ivi_direct_scan_4x4[16] = {
+ 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15
+};
+
/*------------------------------------------------------------------------*/
int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx) {
diff --git a/image/codecs/indeo/indeo.h b/image/codecs/indeo/indeo.h
index c84f257f27..fa1bc2f17d 100644
--- a/image/codecs/indeo/indeo.h
+++ b/image/codecs/indeo/indeo.h
@@ -55,10 +55,21 @@ enum {
IVI4_FRAMETYPE_NULL_LAST = 6 ///< empty frame with no data
};
+typedef void(*ivi_mc_func) (int16 *buf, const int16 *ref_buf,
+ uint32 pitch, int mc_type);
+typedef void(*ivi_mc_avg_func) (int16 *buf, const int16 *ref_buf1,
+ const int16 *ref_buf2,
+ uint32 pitch, int mc_type, int mc_type2);
+
#define IVI_VLC_BITS 13 ///< max number of bits of the ivi's huffman codes
#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)))
+
+/**
* huffman codebook descriptor
*/
struct IVIHuffDesc {
@@ -129,7 +140,6 @@ enum {
//extern const uint8 ff_ivi_horizontal_scan_8x8[64];
//extern const uint8 ff_ivi_direct_scan_4x4[16];
-
/**
* Declare inverse transform function types
*/
@@ -272,6 +282,40 @@ struct IVIPlaneDesc {
static void ivi_free_buffers(IVIPlaneDesc *planes);
};
+struct AVFrame {
+#define AV_NUM_DATA_POINTERS 8
+ /**
+ * 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];
+};
+
struct IVI45DecContext {
GetBits * gb;
RVMapDesc rvmap_tabs[9]; ///< local corrected copy of the static rvmap tables
@@ -310,33 +354,131 @@ struct IVI45DecContext {
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;
+ AVFrame * p_frame;
int got_p_frame;
};
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);
+
+ /**
+ * Sets the frame dimensions
+ */
+ int ff_set_dimensions(uint16 width, uint16 height);
+
+ /**
+ * Get a buffer for a frame. This is a wrapper around
+ * AVCodecContext.get_buffer() and should be used instead calling get_buffer()
+ * directly.
+ */
+ int ff_get_buffer(AVFrame *frame, int flags);
+
+ /**
+ * 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] dst_pitch pitch of the destination buffer
+ */
+ void ff_ivi_recompose_haar(const IVIPlaneDesc *plane, uint8 *dst,
+ const int dst_pitch);
+
+ /**
+ * 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] dst_pitch pitch of the destination buffer
+ */
+ void ff_ivi_recompose53(const IVIPlaneDesc *plane,
+ uint8 *dst, const int dst_pitch);
+
+ /*
+ * 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] dst_pitch pitch for moving to the next y line
+ */
+ void ivi_output_plane(IVIPlaneDesc *plane, uint8 *dst, int dst_pitch);
+
+ /**
+ * 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] mv_scale scaling factor for motion vectors
+ */
+ int ivi_process_empty_tile(IVIBandDesc *band, IVITile *tile, int32 mv_scale);
+
+ /*
+ * 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
+ * @return size of the tile data in bytes
+ */
+ int ivi_dec_tile_data_size(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
+ * @return result code: 0 - OK, -1 = error (corrupted blocks data)
+ */
+ int ivi_decode_blocks(GetBits *gb, IVIBandDesc *band, IVITile *tile);
+
+ int ivi_mc(IVIBandDesc *band, ivi_mc_func mc, ivi_mc_avg_func mc_avg,
+ int offs, int mv_x, int mv_y, int mv_x2, int mv_y2,
+ int mc_type, int mc_type2);
+
+ int ivi_decode_coded_blocks(GetBits *gb, IVIBandDesc *band,
+ ivi_mc_func mc, ivi_mc_avg_func mc_avg, int mv_x, int mv_y,
+ int mv_x2, int mv_y2, int *prev_dc, int is_intra,
+ int mc_type, int mc_type2, uint32 quant, int offs);
+
+ int ivi_dc_transform(IVIBandDesc *band, int *prev_dc, int buf_offs,
+ int blk_size);
protected:
IVI45DecContext _ctx;
Graphics::PixelFormat _pixelFormat;
Graphics::ManagedSurface *_surface;
+
+ /**
+ * Scan patterns shared between indeo4 and indeo5
+ */
+ static const uint8 _ff_ivi_vertical_scan_8x8[64];
+ static const uint8 _ff_ivi_horizontal_scan_8x8[64];
+ static const uint8 _ff_ivi_direct_scan_4x4[16];
protected:
/**
* Returns the pixel format for the decoder's surface
@@ -350,10 +492,40 @@ protected:
virtual int decodePictureHeader() = 0;
/**
+ * Rearrange decoding and reference buffers.
+ */
+ virtual void switch_buffers() = 0;
+
+ virtual bool is_nonnull_frame() const = 0;
+
+ /**
+ * Decode Indeo band header.
+ *
+ * @param[in,out] band pointer to the band descriptor
+ * @return result code: 0 = OK, negative number = error
+ */
+ virtual int decode_band_hdr(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
+ * @return result code: 0 = OK, negative number = error
+ */
+ virtual int decode_mb_info(IVIBandDesc *band, IVITile *tile)= 0;
+
+ /**
* Decodes the Indeo frame from the bit reader already
* loaded into the context
*/
int decodeIndeoFrame();
+
+ /**
+ * scale motion vector
+ */
+ int ivi_scale_mv(int mv, int mv_scale);
public:
IndeoDecoderBase(uint16 width, uint16 height);
virtual ~IndeoDecoderBase();
diff --git a/image/codecs/indeo/indeo_dsp.cpp b/image/codecs/indeo/indeo_dsp.cpp
new file mode 100644
index 0000000000..88e078d5f1
--- /dev/null
+++ b/image/codecs/indeo/indeo_dsp.cpp
@@ -0,0 +1,639 @@
+/* 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::ff_ivi_inverse_haar_8x8(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::ff_ivi_row_haar8(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::ff_ivi_col_haar8(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::ff_ivi_inverse_haar_4x4(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::ff_ivi_row_haar4(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::ff_ivi_col_haar4(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::ff_ivi_dc_haar_2d(const int32 *in, int16 *out, uint32 pitch,
+ int blk_size) {
+ int x, y;
+ int16 dc_coeff;
+
+ dc_coeff = (*in + 0) >> 3;
+
+ for (y = 0; y < blk_size; out += pitch, y++) {
+ for (x = 0; x < blk_size; x++)
+ out[x] = dc_coeff;
+ }
+}
+
+//* 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::ff_ivi_inverse_slant_8x8(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::ff_ivi_inverse_slant_4x4(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::ff_ivi_dc_slant_2d(const int32 *in, int16 *out, uint32 pitch,
+ int blk_size) {
+ int x, y;
+ int16 dc_coeff;
+
+ dc_coeff = (*in + 1) >> 1;
+
+ for (y = 0; y < blk_size; out += pitch, y++) {
+ for (x = 0; x < blk_size; x++)
+ out[x] = dc_coeff;
+ }
+}
+
+void IndeoDSP::ff_ivi_row_slant8(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::ff_ivi_dc_row_slant(const int32 *in, int16 *out, uint32 pitch, int blk_size) {
+ int x, y;
+ int16 dc_coeff;
+
+ dc_coeff = (*in + 1) >> 1;
+
+ for (x = 0; x < blk_size; x++)
+ out[x] = dc_coeff;
+
+ out += pitch;
+
+ for (y = 1; y < blk_size; out += pitch, y++) {
+ for (x = 0; x < blk_size; x++)
+ out[x] = 0;
+ }
+}
+
+void IndeoDSP::ff_ivi_col_slant8(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::ff_ivi_dc_col_slant(const int32 *in, int16 *out, uint32 pitch, int blk_size) {
+ int x, y;
+ int16 dc_coeff;
+
+ dc_coeff = (*in + 1) >> 1;
+
+ for (y = 0; y < blk_size; out += pitch, y++) {
+ out[0] = dc_coeff;
+ for (x = 1; x < blk_size; x++)
+ out[x] = 0;
+ }
+}
+
+void IndeoDSP::ff_ivi_row_slant4(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::ff_ivi_col_slant4(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::ff_ivi_put_pixels_8x8(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::ff_ivi_put_dc_pixel_8x8(const int32 *in, int16 *out, uint32 pitch,
+ int blk_size) {
+ 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 ivi_mc_ ## size ##x## size ## suffix(int16 *buf, \
+ uint32 dpitch, \
+ const int16 *ref_buf, \
+ uint32 pitch, int mc_type) \
+{ \
+ int i, j; \
+ const int16 *wptr; \
+\
+ switch (mc_type) { \
+ case 0: /* fullpel (no interpolation) */ \
+ for (i = 0; i < size; i++, buf += dpitch, ref_buf += pitch) { \
+ for (j = 0; j < size; j++) {\
+ OP(buf[j], ref_buf[j]); \
+ } \
+ } \
+ break; \
+ case 1: /* horizontal halfpel interpolation */ \
+ for (i = 0; i < size; i++, buf += dpitch, ref_buf += pitch) \
+ for (j = 0; j < size; j++) \
+ OP(buf[j], (ref_buf[j] + ref_buf[j+1]) >> 1); \
+ break; \
+ case 2: /* vertical halfpel interpolation */ \
+ wptr = ref_buf + pitch; \
+ for (i = 0; i < size; i++, buf += dpitch, wptr += pitch, ref_buf += pitch) \
+ for (j = 0; j < size; j++) \
+ OP(buf[j], (ref_buf[j] + wptr[j]) >> 1); \
+ break; \
+ case 3: /* vertical and horizontal halfpel interpolation */ \
+ wptr = ref_buf + pitch; \
+ for (i = 0; i < size; i++, buf += dpitch, wptr += pitch, ref_buf += pitch) \
+ for (j = 0; j < size; j++) \
+ OP(buf[j], (ref_buf[j] + ref_buf[j+1] + wptr[j] + wptr[j+1]) >> 2); \
+ break; \
+ } \
+} \
+\
+void IndeoDSP::ff_ivi_mc_ ## size ##x## size ## suffix(int16 *buf, const int16 *ref_buf, \
+ uint32 pitch, int mc_type) \
+{ \
+ ivi_mc_ ## size ##x## size ## suffix(buf, pitch, ref_buf, pitch, mc_type); \
+}
+
+#define IVI_MC_AVG_TEMPLATE(size, suffix, OP) \
+void IndeoDSP::ff_ivi_mc_avg_ ## size ##x## size ## suffix(int16 *buf, \
+ const int16 *ref_buf, \
+ const int16 *ref_buf2, \
+ uint32 pitch, \
+ int mc_type, int mc_type2) \
+{ \
+ int16 tmp[size * size]; \
+ int i, j; \
+\
+ ivi_mc_ ## size ##x## size ## _no_delta(tmp, size, ref_buf, pitch, mc_type); \
+ ivi_mc_ ## size ##x## size ## _delta(tmp, size, ref_buf2, pitch, mc_type2); \
+ 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, _no_delta, OP_PUT)
+IVI_MC_TEMPLATE(8, _delta, OP_ADD)
+IVI_MC_TEMPLATE(4, _no_delta, OP_PUT)
+IVI_MC_TEMPLATE(4, _delta, OP_ADD)
+IVI_MC_AVG_TEMPLATE(8, _no_delta, OP_PUT)
+IVI_MC_AVG_TEMPLATE(8, _delta, OP_ADD)
+IVI_MC_AVG_TEMPLATE(4, _no_delta, 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..fc503397cf
--- /dev/null
+++ b/image/codecs/indeo/indeo_dsp.h
@@ -0,0 +1,338 @@
+/* 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:
+ * 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 ff_ivi_inverse_haar_8x8(const int32 *in, int16 *out, uint32 pitch,
+ const uint8 *flags);
+ static void ff_ivi_inverse_haar_8x1(const int32 *in, int16 *out, uint32 pitch,
+ const uint8 *flags);
+ static void ff_ivi_inverse_haar_1x8(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 ff_ivi_row_haar8(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 ff_ivi_col_haar8(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 ff_ivi_inverse_haar_4x4(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 ff_ivi_row_haar4(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 ff_ivi_col_haar4(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 DC_coeff >> 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] blk_size transform block size
+ */
+ static void ff_ivi_dc_haar_2d(const int32 *in, int16 *out, uint32 pitch,
+ int blk_size);
+
+ /**
+ * 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 ff_ivi_inverse_slant_8x8(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 ff_ivi_inverse_slant_4x4(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 (DC_coeff + 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] blk_size transform block size
+ */
+ static void ff_ivi_dc_slant_2d(const int32 *in, int16 *out, uint32 pitch, int blk_size);
+
+ /**
+ * 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 ff_ivi_row_slant8(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 ff_ivi_col_slant8(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 ff_ivi_row_slant4(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 ff_ivi_col_slant4(const int32 *in, int16 *out, uint32 pitch,
+ const uint8 *flags);
+
+ /**
+ * DC-only inverse row slant transform
+ */
+ static void ff_ivi_dc_row_slant(const int32 *in, int16 *out, uint32 pitch, int blk_size);
+
+ /**
+ * DC-only inverse column slant transform
+ */
+ static void ff_ivi_dc_col_slant(const int32 *in, int16 *out, uint32 pitch, int blk_size);
+
+ /**
+ * Copy the pixels into the frame buffer.
+ */
+ static void ff_ivi_put_pixels_8x8(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 ff_ivi_put_dc_pixel_8x8(const int32 *in, int16 *out, uint32 pitch, int blk_size);
+
+ /**
+ * 8x8 block motion compensation with adding delta
+ *
+ * @param[in,out] buf pointer to the block in the current frame buffer containing delta
+ * @param[in] ref_buf pointer to the corresponding block in the reference frame
+ * @param[in] pitch pitch for moving to the next y line
+ * @param[in] mc_type interpolation type
+ */
+ static void ff_ivi_mc_8x8_delta(int16 *buf, const int16 *ref_buf, uint32 pitch, int mc_type);
+
+ /**
+ * 4x4 block motion compensation with adding delta
+ *
+ * @param[in,out] buf pointer to the block in the current frame buffer containing delta
+ * @param[in] ref_buf pointer to the corresponding block in the reference frame
+ * @param[in] pitch pitch for moving to the next y line
+ * @param[in] mc_type interpolation type
+ */
+ static void ff_ivi_mc_4x4_delta(int16 *buf, const int16 *ref_buf, uint32 pitch, int mc_type);
+
+ /**
+ * motion compensation without adding delta
+ *
+ * @param[in,out] buf pointer to the block in the current frame receiving the result
+ * @param[in] ref_buf pointer to the corresponding block in the reference frame
+ * @param[in] pitch pitch for moving to the next y line
+ * @param[in] mc_type interpolation type
+ */
+ static void ff_ivi_mc_8x8_no_delta(int16 *buf, const int16 *ref_buf, uint32 pitch, int mc_type);
+
+ /**
+ * 4x4 block motion compensation without adding delta
+ *
+ * @param[in,out] buf pointer to the block in the current frame receiving the result
+ * @param[in] ref_buf pointer to the corresponding block in the reference frame
+ * @param[in] pitch pitch for moving to the next y line
+ * @param[in] mc_type interpolation type
+ */
+ static void ff_ivi_mc_4x4_no_delta(int16 *buf, const int16 *ref_buf, uint32 pitch, int mc_type);
+
+ /**
+ * 8x8 block motion compensation with adding delta
+ *
+ * @param[in,out] buf pointer to the block in the current frame buffer containing delta
+ * @param[in] ref_buf pointer to the corresponding block in the backward reference frame
+ * @param[in] ref_buf2 pointer to the corresponding block in the forward reference frame
+ * @param[in] pitch pitch for moving to the next y line
+ * @param[in] mc_type interpolation type for backward reference
+ * @param[in] mc_type2 interpolation type for forward reference
+ */
+ static void ff_ivi_mc_avg_8x8_delta(int16 *buf, const int16 *ref_buf, const int16 *ref_buf2, uint32 pitch, int mc_type, int mc_type2);
+
+ /**
+ * 4x4 block motion compensation with adding delta
+ *
+ * @param[in,out] buf pointer to the block in the current frame buffer containing delta
+ * @param[in] ref_buf pointer to the corresponding block in the backward reference frame
+ * @param[in] ref_buf2 pointer to the corresponding block in the forward reference frame
+ * @param[in] pitch pitch for moving to the next y line
+ * @param[in] mc_type interpolation type for backward reference
+ * @param[in] mc_type2 interpolation type for forward reference
+ */
+ static void ff_ivi_mc_avg_4x4_delta(int16 *buf, const int16 *ref_buf, const int16 *ref_buf2, uint32 pitch, int mc_type, int mc_type2);
+
+ /**
+ * motion compensation without adding delta for B-frames
+ *
+ * @param[in,out] buf pointer to the block in the current frame receiving the result
+ * @param[in] ref_buf pointer to the corresponding block in the backward reference frame
+ * @param[in] ref_buf2 pointer to the corresponding block in the forward reference frame
+ * @param[in] pitch pitch for moving to the next y line
+ * @param[in] mc_type interpolation type for backward reference
+ * @param[in] mc_type2 interpolation type for forward reference
+ */
+ static void ff_ivi_mc_avg_8x8_no_delta(int16 *buf, const int16 *ref_buf, const int16 *ref_buf2, uint32 pitch, int mc_type, int mc_type2);
+
+ /**
+ * 4x4 block motion compensation without adding delta for B-frames
+ *
+ * @param[in,out] buf pointer to the block in the current frame receiving the result
+ * @param[in] ref_buf pointer to the corresponding block in the backward reference frame
+ * @param[in] ref_buf2 pointer to the corresponding block in the forward reference frame
+ * @param[in] pitch pitch for moving to the next y line
+ * @param[in] mc_type interpolation type for backward reference
+ * @param[in] mc_type2 interpolation type for forward reference
+ */
+ static void ff_ivi_mc_avg_4x4_no_delta(int16 *buf, const int16 *ref_buf, const int16 *ref_buf2, uint32 pitch, int mc_type, int mc_type2);
+};
+
+} // End of namespace Indeo
+} // End of namespace Image
+
+#endif
diff --git a/image/codecs/indeo/mem.cpp b/image/codecs/indeo/mem.cpp
index 03a39cabb5..53a3236cf6 100644
--- a/image/codecs/indeo/mem.cpp
+++ b/image/codecs/indeo/mem.cpp
@@ -153,5 +153,29 @@ uint16 inv_bits(uint16 val, int nbits) {
return res;
}
+uint8 av_clip_uint8(int a) {
+ if (a&(~0xFF)) return (-a) >> 31;
+ else return a;
+}
+
+unsigned av_clip_uintp2(int a, int p) {
+ if (a & ~((1 << p) - 1)) return -a >> 31 & ((1 << p) - 1);
+ else return a;
+}
+
+
+/*------------------------------------------------------------------------*/
+
+const uint8 ff_zigzag_direct[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
+};
+
} // End of namespace Indeo
} // End of namespace Image
diff --git a/image/codecs/indeo/mem.h b/image/codecs/indeo/mem.h
index 4f9ebf016d..d3755d652c 100644
--- a/image/codecs/indeo/mem.h
+++ b/image/codecs/indeo/mem.h
@@ -37,6 +37,7 @@ 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)
+#define FFSIGN(a) ((a) > 0 ? 1 : -1)
/**
* Allocate a memory block with alignment suitable for all memory accesses
@@ -139,6 +140,34 @@ extern uint16 inv_bits(uint16 val, int nbits);
*/
extern uint32 bitswap_32(uint32 x);
+/**
+ * Clip a signed integer value into the 0-255 range.
+ * @param a value to clip
+ * @return clipped value
+ */
+extern uint8 av_clip_uint8(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 av_clip_uintp2(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 ff_zigzag_direct[64];
+
} // End of namespace Indeo
} // End of namespace Image
diff --git a/image/codecs/indeo4.cpp b/image/codecs/indeo4.cpp
index 29616e9c63..af521b3ab3 100644
--- a/image/codecs/indeo4.cpp
+++ b/image/codecs/indeo4.cpp
@@ -34,6 +34,7 @@
#include "common/util.h"
#include "graphics/yuv_to_rgb.h"
#include "image/codecs/indeo4.h"
+#include "image/codecs/indeo/mem.h"
namespace Image {
@@ -223,6 +224,373 @@ int Indeo4Decoder::decodePictureHeader() {
return 0;
}
+void Indeo4Decoder::switch_buffers() {
+ int is_prev_ref = 0, is_ref = 0;
+
+ switch (_ctx.prev_frame_type) {
+ case IVI4_FRAMETYPE_INTRA:
+ case IVI4_FRAMETYPE_INTRA1:
+ case IVI4_FRAMETYPE_INTER:
+ is_prev_ref = 1;
+ break;
+ }
+
+ switch (_ctx.frame_type) {
+ case IVI4_FRAMETYPE_INTRA:
+ case IVI4_FRAMETYPE_INTRA1:
+ case IVI4_FRAMETYPE_INTER:
+ is_ref = 1;
+ break;
+
+ default:
+ break;
+ }
+
+ if (is_prev_ref && is_ref) {
+ FFSWAP(int, _ctx.dst_buf, _ctx.ref_buf);
+ }
+ else if (is_prev_ref) {
+ FFSWAP(int, _ctx.ref_buf, _ctx.b_ref_buf);
+ FFSWAP(int, _ctx.dst_buf, _ctx.ref_buf);
+ }
+}
+
+bool Indeo4Decoder::is_nonnull_frame() const {
+ return _ctx.frame_type < IVI4_FRAMETYPE_NULL_FIRST;
+}
+
+int Indeo4Decoder::decode_band_hdr(IVIBandDesc *band) {
+ int plane, band_num, indx, transform_id, scan_indx;
+ int i;
+ int quant_mat;
+
+ plane = _ctx.gb->getBits(2);
+ band_num = _ctx.gb->getBits(4);
+ if (band->plane != plane || band->band_num != band_num) {
+ warning("Invalid band header sequence!");
+ return -1;
+ }
+
+ band->is_empty = _ctx.gb->getBits1();
+ if (!band->is_empty) {
+ int old_blk_size = band->blk_size;
+ // skip header size
+ // If header size is not given, header size is 4 bytes.
+ if (_ctx.gb->getBits1())
+ _ctx.gb->skipBits(16);
+
+ band->is_halfpel = _ctx.gb->getBits(2);
+ if (band->is_halfpel >= 2) {
+ warning("Invalid/unsupported mv resolution: %d!",
+ band->is_halfpel);
+ return -1;
+ }
+ if (!band->is_halfpel)
+ _ctx.uses_fullpel = 1;
+
+ band->checksum_present = _ctx.gb->getBits1();
+ if (band->checksum_present)
+ band->checksum = _ctx.gb->getBits(16);
+
+ indx = _ctx.gb->getBits(2);
+ if (indx == 3) {
+ warning("Invalid block size!");
+ return -1;
+ }
+ band->mb_size = 16 >> indx;
+ band->blk_size = 8 >> (indx >> 1);
+
+ band->inherit_mv = _ctx.gb->getBits1();
+ band->inherit_qdelta = _ctx.gb->getBits1();
+
+ band->glob_quant = _ctx.gb->getBits(5);
+
+ if (!_ctx.gb->getBits1() || _ctx.frame_type == IVI4_FRAMETYPE_INTRA) {
+ transform_id = _ctx.gb->getBits(5);
+ if (transform_id >= FF_ARRAY_ELEMS(_transforms) ||
+ !_transforms[transform_id].inv_trans) {
+ warning("Transform %d", transform_id);
+ return -3;
+ }
+ if ((transform_id >= 7 && transform_id <= 9) ||
+ transform_id == 17) {
+ warning("DCT transform");
+ return -3;
+ }
+
+ if (transform_id < 10 && band->blk_size < 8) {
+ warning("wrong transform size!");
+ return -1;
+ }
+ if ((transform_id >= 0 && transform_id <= 2) || transform_id == 10)
+ _ctx.uses_haar = 1;
+
+ band->inv_transform = _transforms[transform_id].inv_trans;
+ band->dc_transform = _transforms[transform_id].dc_trans;
+ band->is_2d_trans = _transforms[transform_id].is_2d_trans;
+
+ if (transform_id < 10)
+ band->transform_size = 8;
+ else
+ band->transform_size = 4;
+
+ if (band->blk_size != band->transform_size) {
+ warning("transform and block size mismatch (%d != %d)", band->transform_size, band->blk_size);
+ return -1;
+ }
+
+ scan_indx = _ctx.gb->getBits(4);
+ if (scan_indx == 15) {
+ warning("Custom scan pattern encountered!");
+ return -1;
+ }
+ if (scan_indx > 4 && scan_indx < 10) {
+ if (band->blk_size != 4) {
+ warning("mismatching scan table!");
+ return -1;
+ }
+ } else if (band->blk_size != 8) {
+ warning("mismatching scan table!");
+ return -1;
+ }
+
+ band->scan = _scan_index_to_tab[scan_indx];
+ band->scan_size = band->blk_size;
+
+ quant_mat = _ctx.gb->getBits(5);
+ if (quant_mat == 31) {
+ warning("Custom quant matrix encountered!");
+ return -1;
+ }
+ if (quant_mat >= FF_ARRAY_ELEMS(_quant_index_to_tab)) {
+ warning("Quantization matrix %d", quant_mat);
+ return -1;
+ }
+ band->quant_mat = quant_mat;
+ } else {
+ if (old_blk_size != band->blk_size) {
+ warning("The band block size does not match the configuration inherited");
+ return -1;
+ }
+ }
+ if (_quant_index_to_tab[band->quant_mat] > 4 && band->blk_size == 4) {
+ warning("Invalid quant matrix for 4x4 block encountered!");
+ band->quant_mat = 0;
+ return -1;
+ }
+ if (band->scan_size != band->blk_size) {
+ warning("mismatching scan table!");
+ return -1;
+ }
+ if (band->transform_size == 8 && band->blk_size < 8) {
+ warning("mismatching transform_size!");
+ return -1;
+ }
+
+ // decode block huffman codebook
+ if (!_ctx.gb->getBits1())
+ band->blk_vlc.tab = _ctx.blk_vlc.tab;
+ else
+ if (band->blk_vlc.ff_ivi_dec_huff_desc(_ctx.gb, 1, IVI_BLK_HUFF))
+ return -1;
+
+ // select appropriate rvmap table for this band
+ band->rvmap_sel = _ctx.gb->getBits1() ? _ctx.gb->getBits(3) : 8;
+
+ // decode rvmap probability corrections if any
+ band->num_corr = 0; // there is no corrections
+ if (_ctx.gb->getBits1()) {
+ band->num_corr = _ctx.gb->getBits(8); // get number of correction pairs
+ if (band->num_corr > 61) {
+ warning("Too many corrections: %d",
+ band->num_corr);
+ return -1;
+ }
+
+ // read correction pairs
+ for (i = 0; i < band->num_corr * 2; i++)
+ band->corr[i] = _ctx.gb->getBits(8);
+ }
+ }
+
+ if (band->blk_size == 8) {
+ band->intra_base = &_ivi4_quant_8x8_intra[_quant_index_to_tab[band->quant_mat]][0];
+ band->inter_base = &_ivi4_quant_8x8_inter[_quant_index_to_tab[band->quant_mat]][0];
+ } else {
+ band->intra_base = &_ivi4_quant_4x4_intra[_quant_index_to_tab[band->quant_mat]][0];
+ band->inter_base = &_ivi4_quant_4x4_inter[_quant_index_to_tab[band->quant_mat]][0];
+ }
+
+ // Indeo 4 doesn't use scale tables
+ band->intra_scale = NULL;
+ band->inter_scale = NULL;
+
+ _ctx.gb->alignGetBits();
+
+ if (!band->scan) {
+ warning("band->scan not set");
+ return -1;
+ }
+
+ return 0;
+}
+
+int Indeo4Decoder::decode_mb_info(IVIBandDesc *band, IVITile *tile) {
+ int x, y, mv_x, mv_y, mv_delta, offs, mb_offset, blks_per_mb,
+ mv_scale, mb_type_bits, s;
+ IVIMbInfo *mb, *ref_mb;
+ int row_offset = band->mb_size * band->pitch;
+
+ mb = tile->mbs;
+ ref_mb = tile->ref_mbs;
+ offs = tile->ypos * band->pitch + tile->xpos;
+
+ blks_per_mb = band->mb_size != band->blk_size ? 4 : 1;
+ mb_type_bits = _ctx.frame_type == IVI4_FRAMETYPE_BIDIR ? 2 : 1;
+
+ /* scale factor for motion vectors */
+ mv_scale = (_ctx.planes[0].bands[0].mb_size >> 3) - (band->mb_size >> 3);
+ mv_x = mv_y = 0;
+
+ if (((tile->width + band->mb_size - 1) / band->mb_size) * ((tile->height + band->mb_size - 1) / band->mb_size) != tile->num_MBs) {
+ warning("num_MBs mismatch %d %d %d %d", tile->width, tile->height, band->mb_size, tile->num_MBs);
+ return -1;
+ }
+
+ for (y = tile->ypos; y < tile->ypos + tile->height; y += band->mb_size) {
+ mb_offset = offs;
+
+ for (x = tile->xpos; x < tile->xpos + tile->width; x += band->mb_size) {
+ mb->xpos = x;
+ mb->ypos = y;
+ mb->buf_offs = mb_offset;
+ mb->b_mv_x =
+ mb->b_mv_y = 0;
+
+ if (_ctx.gb->getBits1()) {
+ if (_ctx.frame_type == IVI4_FRAMETYPE_INTRA) {
+ warning("Empty macroblock in an INTRA picture!");
+ return -1;
+ }
+ mb->type = 1; // empty macroblocks are always INTER
+ mb->cbp = 0; // all blocks are empty
+
+ mb->q_delta = 0;
+ if (!band->plane && !band->band_num && _ctx.in_q) {
+ mb->q_delta = _ctx.gb->getVLC2(_ctx.mb_vlc.tab->table,
+ IVI_VLC_BITS, 1);
+ mb->q_delta = IVI_TOSIGNED(mb->q_delta);
+ }
+
+ mb->mv_x = mb->mv_y = 0; /* no motion vector coded */
+ if (band->inherit_mv && ref_mb) {
+ /* motion vector inheritance */
+ if (mv_scale) {
+ mb->mv_x = ivi_scale_mv(ref_mb->mv_x, mv_scale);
+ mb->mv_y = ivi_scale_mv(ref_mb->mv_y, mv_scale);
+ }
+ else {
+ mb->mv_x = ref_mb->mv_x;
+ mb->mv_y = ref_mb->mv_y;
+ }
+ }
+ } else {
+ if (band->inherit_mv) {
+ /* copy mb_type from corresponding reference mb */
+ if (!ref_mb) {
+ warning("ref_mb unavailable");
+ return -1;
+ }
+ mb->type = ref_mb->type;
+ }
+ else if (_ctx.frame_type == IVI4_FRAMETYPE_INTRA ||
+ _ctx.frame_type == IVI4_FRAMETYPE_INTRA1) {
+ mb->type = 0; /* mb_type is always INTRA for intra-frames */
+ } else {
+ mb->type = _ctx.gb->getBits(mb_type_bits);
+ }
+
+ mb->cbp = _ctx.gb->getBits(blks_per_mb);
+
+ mb->q_delta = 0;
+ if (band->inherit_qdelta) {
+ if (ref_mb) mb->q_delta = ref_mb->q_delta;
+ }
+ else if (mb->cbp || (!band->plane && !band->band_num &&
+ _ctx.in_q)) {
+ mb->q_delta = _ctx.gb->getVLC2(_ctx.mb_vlc.tab->table,
+ IVI_VLC_BITS, 1);
+ mb->q_delta = IVI_TOSIGNED(mb->q_delta);
+ }
+
+ if (!mb->type) {
+ mb->mv_x = mb->mv_y = 0; /* there is no motion vector in intra-macroblocks */
+ } else {
+ if (band->inherit_mv) {
+ if (ref_mb)
+ /* motion vector inheritance */
+ if (mv_scale) {
+ mb->mv_x = ivi_scale_mv(ref_mb->mv_x, mv_scale);
+ mb->mv_y = ivi_scale_mv(ref_mb->mv_y, mv_scale);
+ }
+ else {
+ mb->mv_x = ref_mb->mv_x;
+ mb->mv_y = ref_mb->mv_y;
+ }
+ } else {
+ /* decode motion vector deltas */
+ mv_delta = _ctx.gb->getVLC2(_ctx.mb_vlc.tab->table,
+ IVI_VLC_BITS, 1);
+ mv_y += IVI_TOSIGNED(mv_delta);
+ mv_delta = _ctx.gb->getVLC2(_ctx.mb_vlc.tab->table,
+ IVI_VLC_BITS, 1);
+ mv_x += IVI_TOSIGNED(mv_delta);
+ mb->mv_x = mv_x;
+ mb->mv_y = mv_y;
+ if (mb->type == 3) {
+ mv_delta = _ctx.gb->getVLC2(
+ _ctx.mb_vlc.tab->table,
+ IVI_VLC_BITS, 1);
+ mv_y += IVI_TOSIGNED(mv_delta);
+ mv_delta = _ctx.gb->getVLC2(
+ _ctx.mb_vlc.tab->table,
+ IVI_VLC_BITS, 1);
+ mv_x += IVI_TOSIGNED(mv_delta);
+ mb->b_mv_x = -mv_x;
+ mb->b_mv_y = -mv_y;
+ }
+ }
+ if (mb->type == 2) {
+ mb->b_mv_x = -mb->mv_x;
+ mb->b_mv_y = -mb->mv_y;
+ mb->mv_x = 0;
+ mb->mv_y = 0;
+ }
+ }
+ }
+
+ s = band->is_halfpel;
+ if (mb->type)
+ if (x + (mb->mv_x >> s) + (y + (mb->mv_y >> s))*band->pitch < 0 ||
+ x + ((mb->mv_x + s) >> s) + band->mb_size - 1
+ + (y + band->mb_size - 1 + ((mb->mv_y + s) >> s))*band->pitch > band->bufsize - 1) {
+ warning("motion vector %d %d outside reference", x*s + mb->mv_x, y*s + mb->mv_y);
+ return -1;
+ }
+
+ mb++;
+ if (ref_mb)
+ ref_mb++;
+ mb_offset += band->mb_size;
+ }
+
+ offs += row_offset;
+ }
+
+ _ctx.gb->alignGetBits();
+ return 0;
+}
+
int Indeo4Decoder::scaleTileSize(int def_size, int size_factor) {
return size_factor == 15 ? def_size : (size_factor + 1) << 5;
}
@@ -245,8 +613,334 @@ int Indeo4Decoder::decodePlaneSubdivision() {
/*------------------------------------------------------------------------*/
+/**
+ * Indeo 4 8x8 scan (zigzag) patterns
+ */
+static const uint8 ivi4_alternate_scan_8x8[64] = {
+ 0, 8, 1, 9, 16, 24, 2, 3, 17, 25, 10, 11, 32, 40, 48, 56,
+ 4, 5, 6, 7, 33, 41, 49, 57, 18, 19, 26, 27, 12, 13, 14, 15,
+ 34, 35, 43, 42, 50, 51, 59, 58, 20, 21, 22, 23, 31, 30, 29, 28,
+ 36, 37, 38, 39, 47, 46, 45, 44, 52, 53, 54, 55, 63, 62, 61, 60
+};
+
+static const uint8 ivi4_alternate_scan_4x4[16] = {
+ 0, 1, 4, 5, 8, 12, 2, 3, 9, 13, 6, 7, 10, 11, 14, 15
+};
+
+static const uint8 ivi4_vertical_scan_4x4[16] = {
+ 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15
+};
+
+static const uint8 ivi4_horizontal_scan_4x4[16] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+};
+
const uint Indeo4Decoder::_ivi4_common_pic_sizes[14] = {
640, 480, 320, 240, 160, 120, 704, 480, 352, 240, 352, 288, 176, 144
};
+Indeo4Decoder::Transform Indeo4Decoder::_transforms[18] = {
+ { IndeoDSP::ff_ivi_inverse_haar_8x8, IndeoDSP::ff_ivi_dc_haar_2d, 1 },
+ { IndeoDSP::ff_ivi_row_haar8, IndeoDSP::ff_ivi_dc_haar_2d, 0 },
+ { IndeoDSP::ff_ivi_col_haar8, IndeoDSP::ff_ivi_dc_haar_2d, 0 },
+ { IndeoDSP::ff_ivi_put_pixels_8x8, IndeoDSP::ff_ivi_put_dc_pixel_8x8, 1 },
+ { IndeoDSP::ff_ivi_inverse_slant_8x8, IndeoDSP::ff_ivi_dc_slant_2d, 1 },
+ { IndeoDSP::ff_ivi_row_slant8, IndeoDSP::ff_ivi_dc_row_slant, 1 },
+ { IndeoDSP::ff_ivi_col_slant8, IndeoDSP::ff_ivi_dc_col_slant, 1 },
+ { NULL, NULL, 0 }, // inverse DCT 8x8
+ { NULL, NULL, 0 }, // inverse DCT 8x1
+ { NULL, NULL, 0 }, // inverse DCT 1x8
+ { IndeoDSP::ff_ivi_inverse_haar_4x4, IndeoDSP::ff_ivi_dc_haar_2d, 1 },
+ { IndeoDSP::ff_ivi_inverse_slant_4x4, IndeoDSP::ff_ivi_dc_slant_2d, 1 },
+ { NULL, NULL, 0 }, // no transform 4x4
+ { IndeoDSP::ff_ivi_row_haar4, IndeoDSP::ff_ivi_dc_haar_2d, 0 },
+ { IndeoDSP::ff_ivi_col_haar4, IndeoDSP::ff_ivi_dc_haar_2d, 0 },
+ { IndeoDSP::ff_ivi_row_slant4, IndeoDSP::ff_ivi_dc_row_slant, 0 },
+ { IndeoDSP::ff_ivi_col_slant4, IndeoDSP::ff_ivi_dc_col_slant, 0 },
+ { NULL, NULL, 0 }, // inverse DCT 4x4
+};
+
+const uint8 *const Indeo4Decoder::_scan_index_to_tab[15] = {
+ // for 8x8 transforms
+ ff_zigzag_direct,
+ ivi4_alternate_scan_8x8,
+ _ff_ivi_horizontal_scan_8x8,
+ _ff_ivi_vertical_scan_8x8,
+ ff_zigzag_direct,
+
+ // for 4x4 transforms
+ _ff_ivi_direct_scan_4x4,
+ ivi4_alternate_scan_4x4,
+ ivi4_vertical_scan_4x4,
+ ivi4_horizontal_scan_4x4,
+ _ff_ivi_direct_scan_4x4,
+
+ // TODO: check if those are needed
+ _ff_ivi_horizontal_scan_8x8,
+ _ff_ivi_horizontal_scan_8x8,
+ _ff_ivi_horizontal_scan_8x8,
+ _ff_ivi_horizontal_scan_8x8,
+ _ff_ivi_horizontal_scan_8x8
+};
+
+/**
+ * Indeo 4 dequant tables
+ */
+const uint16 Indeo4Decoder::_ivi4_quant_8x8_intra[9][64] = {
+ {
+ 43, 342, 385, 470, 555, 555, 598, 726,
+ 342, 342, 470, 513, 555, 598, 726, 769,
+ 385, 470, 555, 555, 598, 726, 726, 811,
+ 470, 470, 555, 555, 598, 726, 769, 854,
+ 470, 555, 555, 598, 683, 726, 854, 1025,
+ 555, 555, 598, 683, 726, 854, 1025, 1153,
+ 555, 555, 598, 726, 811, 982, 1195, 1451,
+ 555, 598, 726, 811, 982, 1195, 1451, 1793
+ },
+ {
+ 86, 1195, 2390, 2390, 4865, 4865, 4865, 4865,
+ 1195, 1195, 2390, 2390, 4865, 4865, 4865, 4865,
+ 2390, 2390, 4865, 4865, 6827, 6827, 6827, 6827,
+ 2390, 2390, 4865, 4865, 6827, 6827, 6827, 6827,
+ 4865, 4865, 6827, 6827, 6827, 6827, 6827, 6827,
+ 4865, 4865, 6827, 6827, 6827, 6827, 6827, 6827,
+ 4865, 4865, 6827, 6827, 6827, 6827, 6827, 6827,
+ 4865, 4865, 6827, 6827, 6827, 6827, 6827, 6827
+ },
+ {
+ 235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+ 235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+ 235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+ 235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+ 235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+ 235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+ 235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+ 235, 1067, 1195, 1323, 1451, 1579, 1707, 1835
+ },
+ {
+ 1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+ 1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+ 1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+ 1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+ 1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+ 1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+ 1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+ 1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414
+ },
+ {
+ 897, 897, 897, 897, 897, 897, 897, 897,
+ 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067,
+ 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238,
+ 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409,
+ 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579,
+ 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
+ 1921, 1921, 1921, 1921, 1921, 1921, 1921, 1921,
+ 2091, 2091, 2091, 2091, 2091, 2091, 2091, 2091
+ },
+ {
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+ 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+ 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+ 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+ 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+ 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414
+ },
+ {
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390
+ },
+ {
+ 22, 171, 214, 257, 257, 299, 299, 342,
+ 171, 171, 257, 257, 299, 299, 342, 385,
+ 214, 257, 257, 299, 299, 342, 342, 385,
+ 257, 257, 257, 299, 299, 342, 385, 427,
+ 257, 257, 299, 299, 342, 385, 427, 513,
+ 257, 299, 299, 342, 385, 427, 513, 598,
+ 299, 299, 299, 385, 385, 470, 598, 726,
+ 299, 299, 385, 385, 470, 598, 726, 897
+ },
+ {
+ 86, 598, 1195, 1195, 2390, 2390, 2390, 2390,
+ 598, 598, 1195, 1195, 2390, 2390, 2390, 2390,
+ 1195, 1195, 2390, 2390, 3414, 3414, 3414, 3414,
+ 1195, 1195, 2390, 2390, 3414, 3414, 3414, 3414,
+ 2390, 2390, 3414, 3414, 3414, 3414, 3414, 3414,
+ 2390, 2390, 3414, 3414, 3414, 3414, 3414, 3414,
+ 2390, 2390, 3414, 3414, 3414, 3414, 3414, 3414,
+ 2390, 2390, 3414, 3414, 3414, 3414, 3414, 3414
+ }
+};
+
+const uint16 Indeo4Decoder::_ivi4_quant_8x8_inter[9][64] = {
+ {
+ 427, 427, 470, 427, 427, 427, 470, 470,
+ 427, 427, 470, 427, 427, 427, 470, 470,
+ 470, 470, 470, 470, 470, 470, 470, 470,
+ 427, 427, 470, 470, 427, 427, 470, 470,
+ 427, 427, 470, 427, 427, 427, 470, 470,
+ 427, 427, 470, 427, 427, 427, 470, 470,
+ 470, 470, 470, 470, 470, 470, 470, 470,
+ 470, 470, 470, 470, 470, 470, 470, 470
+ },
+ {
+ 1707, 1707, 2433, 2433, 3414, 3414, 3414, 3414,
+ 1707, 1707, 2433, 2433, 3414, 3414, 3414, 3414,
+ 2433, 2433, 3414, 3414, 4822, 4822, 4822, 4822,
+ 2433, 2433, 3414, 3414, 4822, 4822, 4822, 4822,
+ 3414, 3414, 4822, 4822, 3414, 3414, 3414, 3414,
+ 3414, 3414, 4822, 4822, 3414, 3414, 3414, 3414,
+ 3414, 3414, 4822, 4822, 3414, 3414, 3414, 3414,
+ 3414, 3414, 4822, 4822, 3414, 3414, 3414, 3414
+ },
+ {
+ 1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+ 1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+ 1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+ 1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+ 1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+ 1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+ 1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+ 1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281
+ },
+ {
+ 2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+ 2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+ 2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+ 2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+ 2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+ 2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+ 2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+ 2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433
+ },
+ {
+ 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195,
+ 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195,
+ 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281,
+ 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238,
+ 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195,
+ 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195,
+ 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281,
+ 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281
+ },
+ {
+ 2433, 2433, 2433, 2433, 2433, 2433, 2433, 2433,
+ 2433, 2433, 2433, 2433, 2433, 2433, 2433, 2433,
+ 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+ 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+ 2433, 2433, 2433, 2433, 2433, 2433, 2433, 2433,
+ 2433, 2433, 2433, 2433, 2433, 2433, 2433, 2433,
+ 2433, 2433, 2433, 2433, 2433, 2433, 2433, 2433,
+ 2433, 2433, 2433, 2433, 2433, 2433, 2433, 2433
+ },
+ {
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707
+ },
+ {
+ 86, 171, 171, 214, 214, 214, 214, 257,
+ 171, 171, 214, 214, 214, 214, 257, 257,
+ 171, 214, 214, 214, 214, 257, 257, 257,
+ 214, 214, 214, 214, 257, 257, 257, 299,
+ 214, 214, 214, 257, 257, 257, 299, 299,
+ 214, 214, 257, 257, 257, 299, 299, 299,
+ 214, 257, 257, 257, 299, 299, 299, 342,
+ 257, 257, 257, 299, 299, 299, 342, 342
+ },
+ {
+ 854, 854, 1195, 1195, 1707, 1707, 1707, 1707,
+ 854, 854, 1195, 1195, 1707, 1707, 1707, 1707,
+ 1195, 1195, 1707, 1707, 2390, 2390, 2390, 2390,
+ 1195, 1195, 1707, 1707, 2390, 2390, 2390, 2390,
+ 1707, 1707, 2390, 2390, 1707, 1707, 1707, 1707,
+ 1707, 1707, 2390, 2390, 1707, 1707, 1707, 1707,
+ 1707, 1707, 2390, 2390, 1707, 1707, 1707, 1707,
+ 1707, 1707, 2390, 2390, 1707, 1707, 1707, 1707
+ }
+};
+
+const uint16 Indeo4Decoder::_ivi4_quant_4x4_intra[5][16] = {
+ {
+ 22, 214, 257, 299,
+ 214, 257, 299, 342,
+ 257, 299, 342, 427,
+ 299, 342, 427, 513
+ },
+ {
+ 129, 1025, 1451, 1451,
+ 1025, 1025, 1451, 1451,
+ 1451, 1451, 2049, 2049,
+ 1451, 1451, 2049, 2049
+ },
+ {
+ 43, 171, 171, 171,
+ 43, 171, 171, 171,
+ 43, 171, 171, 171,
+ 43, 171, 171, 171
+ },
+ {
+ 43, 43, 43, 43,
+ 171, 171, 171, 171,
+ 171, 171, 171, 171,
+ 171, 171, 171, 171
+ },
+ {
+ 43, 43, 43, 43,
+ 43, 43, 43, 43,
+ 43, 43, 43, 43,
+ 43, 43, 43, 43
+ }
+};
+
+const uint16 Indeo4Decoder::_ivi4_quant_4x4_inter[5][16] = {
+ {
+ 107, 214, 257, 299,
+ 214, 257, 299, 299,
+ 257, 299, 299, 342,
+ 299, 299, 342, 342
+ },
+ {
+ 513, 1025, 1238, 1238,
+ 1025, 1025, 1238, 1238,
+ 1238, 1238, 1451, 1451,
+ 1238, 1238, 1451, 1451
+ },
+ {
+ 43, 171, 171, 171,
+ 43, 171, 171, 171,
+ 43, 171, 171, 171,
+ 43, 171, 171, 171
+ },
+ {
+ 43, 43, 43, 43,
+ 171, 171, 171, 171,
+ 171, 171, 171, 171,
+ 171, 171, 171, 171
+ },
+ {
+ 43, 43, 43, 43,
+ 43, 43, 43, 43,
+ 43, 43, 43, 43,
+ 43, 43, 43, 43
+ }
+};
+
+const uint8 Indeo4Decoder::_quant_index_to_tab[22] = {
+ 0, 1, 0, 2, 1, 3, 0, 4, 1, 5, 0, 1, 6, 7, 8, // for 8x8 quant matrixes
+ 0, 1, 2, 2, 3, 3, 4 // for 4x4 quant matrixes
+};
+
} // End of namespace Image
diff --git a/image/codecs/indeo4.h b/image/codecs/indeo4.h
index b2d89d5d55..1034f18f0c 100644
--- a/image/codecs/indeo4.h
+++ b/image/codecs/indeo4.h
@@ -35,6 +35,7 @@
#include "image/codecs/indeo/get_bits.h"
#include "image/codecs/indeo/indeo.h"
+#include "image/codecs/indeo/indeo_dsp.h"
#include "graphics/managed_surface.h"
namespace Image {
@@ -50,6 +51,11 @@ using namespace Indeo;
* - AVIDecoder
*/
class Indeo4Decoder : public IndeoDecoderBase {
+ struct Transform {
+ InvTransformPtr *inv_trans;
+ DCTransformPtr *dc_trans;
+ int is_2d_trans;
+ };
public:
Indeo4Decoder(uint16 width, uint16 height);
virtual ~Indeo4Decoder() {}
@@ -63,6 +69,31 @@ protected:
* @returns 0 = Ok, negative number = error
*/
virtual int decodePictureHeader();
+
+ /**
+ * Rearrange decoding and reference buffers.
+ */
+ virtual void switch_buffers();
+
+ virtual bool is_nonnull_frame() const;
+
+ /**
+ * Decode Indeo 4 band header.
+ *
+ * @param[in,out] band pointer to the band descriptor
+ * @return result code: 0 = OK, negative number = error
+ */
+ virtual int decode_band_hdr(IVIBandDesc *band);
+
+ /**
+ * Decode information (block type, cbp, quant delta, motion vector)
+ * for all macroblocks in the current tile.
+ *
+ * @param[in,out] band pointer to the band descriptor
+ * @param[in,out] tile pointer to the tile descriptor
+ * @return result code: 0 = OK, negative number = error
+ */
+ virtual int decode_mb_info(IVIBandDesc *band, IVITile *tile);
private:
int scaleTileSize(int def_size, int size_factor);
@@ -83,6 +114,30 @@ private:
* Standard picture dimensions
*/
static const uint _ivi4_common_pic_sizes[14];
+
+ /**
+ * Transformations list
+ */
+ static Transform _transforms[18];
+
+ static const uint8 *const _scan_index_to_tab[15];
+
+ /**
+ * Indeo 4 dequant tables
+ */
+ static const uint16 _ivi4_quant_8x8_intra[9][64];
+
+ static const uint16 _ivi4_quant_8x8_inter[9][64];
+
+ static const uint16 _ivi4_quant_4x4_intra[5][16];
+
+ static const uint16 _ivi4_quant_4x4_inter[5][16];
+
+ /**
+ * Table for mapping quant matrix index from the bitstream
+ * into internal quant table number.
+ */
+ static const uint8 _quant_index_to_tab[22];
};
} // End of namespace Image
diff --git a/image/module.mk b/image/module.mk
index 6d55b17240..03ba4d1762 100644
--- a/image/module.mk
+++ b/image/module.mk
@@ -25,6 +25,7 @@ MODULE_OBJS := \
codecs/truemotion1.o \
codecs/indeo/get_bits.o \
codecs/indeo/indeo.o \
+ codecs/indeo/indeo_dsp.o \
codecs/indeo/mem.o \
codecs/indeo/vlc.o