diff options
Diffstat (limited to 'image/codecs/indeo/indeo.cpp')
-rw-r--r-- | image/codecs/indeo/indeo.cpp | 883 |
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) { |