X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fimm4.c;h=d92bc30ddcbc10eb7942ff66addce81f02a75f22;hb=9d6be83085ccb1f52b923064eb93566ddbb0a1f7;hp=4769f352e9bab9571c7f47d39f6f68851b0f2152;hpb=768b07e3bca7e81d2f9c60badb3973d3d88481dc;p=ffmpeg diff --git a/libavcodec/imm4.c b/libavcodec/imm4.c index 4769f352e9b..d92bc30ddcb 100644 --- a/libavcodec/imm4.c +++ b/libavcodec/imm4.c @@ -41,16 +41,17 @@ typedef struct IMM4Context { uint8_t *bitstream; int bitstream_size; - int changed_size; int factor; - unsigned sindex; + unsigned lo; + unsigned hi; + ScanTable intra_scantable; DECLARE_ALIGNED(32, int16_t, block)[6][64]; IDCTDSPContext idsp; } IMM4Context; static const uint8_t intra_cb[] = { - 12, 9, 6 + 24, 18, 12 }; static const uint8_t inter_cb[] = { @@ -137,9 +138,10 @@ static int get_cbphi(GetBitContext *gb, int x) } static int decode_block(AVCodecContext *avctx, GetBitContext *gb, - int block, int factor, int flag) + int block, int factor, int flag, int offset, int flag2) { IMM4Context *s = avctx->priv_data; + const uint8_t *scantable = s->intra_scantable.permutated; int i, last, len, factor2; for (i = !flag; i < 64; i++) { @@ -162,18 +164,27 @@ static int decode_block(AVCodecContext *avctx, GetBitContext *gb, i += len; if (i >= 64) break; - s->block[block][i] = factor * factor2; + s->block[block][scantable[i]] = offset * (factor2 < 0 ? -1 : 1) + factor * factor2; if (last) break; } + if (s->hi == 2 && flag2 && block < 4) { + if (flag) + s->block[block][scantable[0]] *= 2; + s->block[block][scantable[1]] *= 2; + s->block[block][scantable[8]] *= 2; + s->block[block][scantable[16]] *= 2; + } + return 0; } static int decode_blocks(AVCodecContext *avctx, GetBitContext *gb, - unsigned cbp, int flag) + unsigned cbp, int flag, int offset, unsigned flag2) { IMM4Context *s = avctx->priv_data; + const uint8_t *scantable = s->intra_scantable.permutated; int ret, i; memset(s->block, 0, sizeof(s->block)); @@ -186,11 +197,11 @@ static int decode_blocks(AVCodecContext *avctx, GetBitContext *gb, x = 128; x *= 8; - s->block[i][0] = x; + s->block[i][scantable[0]] = x; } if (cbp & (1 << (5 - i))) { - ret = decode_block(avctx, gb, i, s->factor, flag); + ret = decode_block(avctx, gb, i, s->factor, flag, offset, flag2); if (ret < 0) return ret; } @@ -202,20 +213,33 @@ static int decode_blocks(AVCodecContext *avctx, GetBitContext *gb, static int decode_intra(AVCodecContext *avctx, GetBitContext *gb, AVFrame *frame) { IMM4Context *s = avctx->priv_data; - int ret, x, y; + int ret, x, y, offset = 0; - s->factor = intra_cb[s->sindex] * 2; + if (s->hi == 0) { + if (s->lo > 2) + return AVERROR_INVALIDDATA; + s->factor = intra_cb[s->lo]; + } else { + s->factor = s->lo * 2; + } + + if (s->hi) { + offset = s->factor; + offset >>= 1; + if (!(offset & 1)) + offset--; + } for (y = 0; y < avctx->height; y += 16) { for (x = 0; x < avctx->width; x += 16) { - unsigned cbphi, cbplo; + unsigned flag, cbphi, cbplo; cbplo = get_vlc2(gb, cbplo_tab.table, cbplo_tab.bits, 1) >> 4; - skip_bits1(gb); + flag = get_bits1(gb); cbphi = get_cbphi(gb, 1); - ret = decode_blocks(avctx, gb, cbplo | (cbphi << 2), 0); + ret = decode_blocks(avctx, gb, cbplo | (cbphi << 2), 0, offset, flag); if (ret < 0) return ret; @@ -241,14 +265,27 @@ static int decode_inter(AVCodecContext *avctx, GetBitContext *gb, AVFrame *frame, AVFrame *prev) { IMM4Context *s = avctx->priv_data; - int ret, x, y; + int ret, x, y, offset = 0; - s->factor = inter_cb[s->sindex]; + if (s->hi == 0) { + if (s->lo > 2) + return AVERROR_INVALIDDATA; + s->factor = inter_cb[s->lo]; + } else { + s->factor = s->lo * 2; + } + + if (s->hi) { + offset = s->factor; + offset >>= 1; + if (!(offset & 1)) + offset--; + } for (y = 0; y < avctx->height; y += 16) { for (x = 0; x < avctx->width; x += 16) { int reverse, intra_block, value; - unsigned cbphi, cbplo; + unsigned cbphi, cbplo, flag2 = 0; if (get_bits1(gb)) { copy_block16(frame->data[0] + y * frame->linesize[0] + x, @@ -270,12 +307,12 @@ static int decode_inter(AVCodecContext *avctx, GetBitContext *gb, intra_block = value & 0x07; reverse = intra_block == 3; if (reverse) - skip_bits1(gb); + flag2 = get_bits1(gb); cbplo = value >> 4; cbphi = get_cbphi(gb, reverse); if (intra_block) { - ret = decode_blocks(avctx, gb, cbplo | (cbphi << 2), 0); + ret = decode_blocks(avctx, gb, cbplo | (cbphi << 2), 0, offset, flag2); if (ret < 0) return ret; @@ -292,8 +329,9 @@ static int decode_inter(AVCodecContext *avctx, GetBitContext *gb, s->idsp.idct_put(frame->data[2] + (y >> 1) * frame->linesize[2] + (x >> 1), frame->linesize[2], s->block[5]); } else { - skip_bits(gb, 2); - ret = decode_blocks(avctx, gb, cbplo | (cbphi << 2), 1); + flag2 = get_bits1(gb); + skip_bits1(gb); + ret = decode_blocks(avctx, gb, cbplo | (cbphi << 2), 1, offset, flag2); if (ret < 0) return ret; @@ -332,6 +370,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, IMM4Context *s = avctx->priv_data; GetBitContext *gb = &s->gb; AVFrame *frame = data; + int width, height; unsigned type; int ret, scaled; @@ -353,9 +392,11 @@ static int decode_frame(AVCodecContext *avctx, void *data, avctx->pix_fmt = AV_PIX_FMT_YUV420P; avctx->color_range = AVCOL_RANGE_JPEG; + width = avctx->width; + height = avctx->height; + scaled = avpkt->data[8]; if (scaled < 2) { - int width, height; int mode = avpkt->data[10]; switch (mode) { @@ -384,22 +425,12 @@ static int decode_frame(AVCodecContext *avctx, void *data, height = 576; break; } - - if (s->changed_size == 1 && - (avctx->width != width || avctx->height != height)) { - av_log(avctx, AV_LOG_ERROR, "Frame size change is unsupported.\n"); - return AVERROR_INVALIDDATA; - } - avctx->width = width; - avctx->height = height; } - s->changed_size = 1; skip_bits_long(gb, 24 * 8); type = get_bits_long(gb, 32); - s->sindex = get_bits_long(gb, 32); - if (s->sindex > 2) - return AVERROR_INVALIDDATA; + s->hi = get_bits(gb, 16); + s->lo = get_bits(gb, 16); switch (type) { case 0x19781977: @@ -415,6 +446,19 @@ static int decode_frame(AVCodecContext *avctx, void *data, return AVERROR_PATCHWELCOME; } + if (avctx->width != width || + avctx->height != height) { + if (!frame->key_frame) { + av_log(avctx, AV_LOG_ERROR, "Frame size change is unsupported.\n"); + return AVERROR_INVALIDDATA; + } + av_frame_unref(s->prev_frame); + } + + ret = ff_set_dimensions(avctx, width, height); + if (ret < 0) + return ret; + if ((ret = ff_get_buffer(avctx, frame, frame->key_frame ? AV_GET_BUFFER_FLAG_REF : 0)) < 0) return ret; @@ -461,10 +505,14 @@ static av_cold int decode_init(AVCodecContext *avctx) { static AVOnce init_static_once = AV_ONCE_INIT; IMM4Context *s = avctx->priv_data; + uint8_t table[64]; + + for (int i = 0; i < 64; i++) + table[i] = i; - avctx->idct_algo = FF_IDCT_FAAN; ff_bswapdsp_init(&s->bdsp); ff_idctdsp_init(&s->idsp, avctx); + ff_init_scantable(s->idsp.idct_permutation, &s->intra_scantable, table); s->prev_frame = av_frame_alloc(); if (!s->prev_frame) @@ -475,6 +523,13 @@ static av_cold int decode_init(AVCodecContext *avctx) return 0; } +static void decode_flush(AVCodecContext *avctx) +{ + IMM4Context *s = avctx->priv_data; + + av_frame_unref(s->prev_frame); +} + static av_cold int decode_close(AVCodecContext *avctx) { IMM4Context *s = avctx->priv_data; @@ -495,6 +550,7 @@ AVCodec ff_imm4_decoder = { .init = decode_init, .close = decode_close, .decode = decode_frame, + .flush = decode_flush, .capabilities = AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,