aboutsummaryrefslogtreecommitdiff
path: root/image/codecs/indeo/indeo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'image/codecs/indeo/indeo.cpp')
-rw-r--r--image/codecs/indeo/indeo.cpp883
1 files changed, 872 insertions, 11 deletions
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) {