IMAGE: Further implementation of Indeo image decoding

This commit is contained in:
Paul Gilbert 2016-09-06 22:13:56 -04:00
parent c165826316
commit 9e774af4d9
11 changed files with 2835 additions and 22 deletions

View File

@ -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);

View File

@ -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();

View File

@ -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;
}
// TODO
switch_buffers();
return err;
//{ 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;
}
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;
}
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) {

View File

@ -55,9 +55,20 @@ 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
*/
@ -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
@ -349,11 +491,41 @@ 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();

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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