diff options
-rw-r--r-- | image/codecs/indeo/get_bits.cpp | 2 | ||||
-rw-r--r-- | image/codecs/indeo/get_bits.h | 2 | ||||
-rw-r--r-- | image/codecs/indeo/indeo.cpp | 883 | ||||
-rw-r--r-- | image/codecs/indeo/indeo.h | 190 | ||||
-rw-r--r-- | image/codecs/indeo/indeo_dsp.cpp | 639 | ||||
-rw-r--r-- | image/codecs/indeo/indeo_dsp.h | 338 | ||||
-rw-r--r-- | image/codecs/indeo/mem.cpp | 24 | ||||
-rw-r--r-- | image/codecs/indeo/mem.h | 29 | ||||
-rw-r--r-- | image/codecs/indeo4.cpp | 694 | ||||
-rw-r--r-- | image/codecs/indeo4.h | 55 | ||||
-rw-r--r-- | image/module.mk | 1 |
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 |