diff options
Diffstat (limited to 'libavcodec/fic.c')
-rw-r--r-- | libavcodec/fic.c | 158 |
1 files changed, 94 insertions, 64 deletions
diff --git a/libavcodec/fic.c b/libavcodec/fic.c index a038af6e60..dcf0777674 100644 --- a/libavcodec/fic.c +++ b/libavcodec/fic.c @@ -4,29 +4,29 @@ * Copyright (c) 2014 Konstantin Shishkov * Copyright (c) 2014 Derek Buitenhuis * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libavutil/common.h" - +#include "libavutil/opt.h" #include "avcodec.h" -#include "bitstream.h" -#include "golomb.h" #include "internal.h" +#include "get_bits.h" +#include "golomb.h" typedef struct FICThreadContext { DECLARE_ALIGNED(16, int16_t, block)[64]; @@ -34,9 +34,11 @@ typedef struct FICThreadContext { int slice_h; int src_size; int y_off; + int p_frame; } FICThreadContext; typedef struct FICContext { + AVClass *class; AVCodecContext *avctx; AVFrame *frame; AVFrame *final_frame; @@ -52,6 +54,7 @@ typedef struct FICContext { int num_slices, slice_h; uint8_t cursor_buf[4096]; + int skip_cursor; } FICContext; static const uint8_t fic_qmat_hq[64] = { @@ -79,29 +82,30 @@ static const uint8_t fic_qmat_lq[64] = { static const uint8_t fic_header[7] = { 0, 0, 1, 'F', 'I', 'C', 'V' }; #define FIC_HEADER_SIZE 27 +#define CURSOR_OFFSET 59 -static av_always_inline void fic_idct(int16_t *blk, int step, int shift) +static av_always_inline void fic_idct(int16_t *blk, int step, int shift, int rnd) { - const int t0 = 27246 * blk[3 * step] + 18405 * blk[5 * step]; - const int t1 = 27246 * blk[5 * step] - 18405 * blk[3 * step]; - const int t2 = 6393 * blk[7 * step] + 32139 * blk[1 * step]; - const int t3 = 6393 * blk[1 * step] - 32139 * blk[7 * step]; - const int t4 = 5793 * (t2 + t0 + 0x800 >> 12); - const int t5 = 5793 * (t3 + t1 + 0x800 >> 12); - const int t6 = t2 - t0; - const int t7 = t3 - t1; - const int t8 = 17734 * blk[2 * step] - 42813 * blk[6 * step]; - const int t9 = 17734 * blk[6 * step] + 42814 * blk[2 * step]; - const int tA = (blk[0 * step] - blk[4 * step] << 15) + (1 << shift - 1); - const int tB = (blk[0 * step] + blk[4 * step] << 15) + (1 << shift - 1); - blk[0 * step] = ( t4 + t9 + tB) >> shift; - blk[1 * step] = ( t6 + t7 + t8 + tA) >> shift; - blk[2 * step] = ( t6 - t7 - t8 + tA) >> shift; - blk[3 * step] = ( t5 - t9 + tB) >> shift; - blk[4 * step] = ( -t5 - t9 + tB) >> shift; - blk[5 * step] = (-(t6 - t7) - t8 + tA) >> shift; - blk[6 * step] = (-(t6 + t7) + t8 + tA) >> shift; - blk[7 * step] = ( -t4 + t9 + tB) >> shift; + const unsigned t0 = 27246 * blk[3 * step] + 18405 * blk[5 * step]; + const unsigned t1 = 27246 * blk[5 * step] - 18405 * blk[3 * step]; + const unsigned t2 = 6393 * blk[7 * step] + 32139 * blk[1 * step]; + const unsigned t3 = 6393 * blk[1 * step] - 32139 * blk[7 * step]; + const unsigned t4 = 5793U * ((int)(t2 + t0 + 0x800) >> 12); + const unsigned t5 = 5793U * ((int)(t3 + t1 + 0x800) >> 12); + const unsigned t6 = t2 - t0; + const unsigned t7 = t3 - t1; + const unsigned t8 = 17734 * blk[2 * step] - 42813 * blk[6 * step]; + const unsigned t9 = 17734 * blk[6 * step] + 42814 * blk[2 * step]; + const unsigned tA = (blk[0 * step] - blk[4 * step]) * 32768 + rnd; + const unsigned tB = (blk[0 * step] + blk[4 * step]) * 32768 + rnd; + blk[0 * step] = (int)( t4 + t9 + tB) >> shift; + blk[1 * step] = (int)( t6 + t7 + t8 + tA) >> shift; + blk[2 * step] = (int)( t6 - t7 - t8 + tA) >> shift; + blk[3 * step] = (int)( t5 - t9 + tB) >> shift; + blk[4 * step] = (int)( -t5 - t9 + tB) >> shift; + blk[5 * step] = (int)(-(t6 - t7) - t8 + tA) >> shift; + blk[6 * step] = (int)(-(t6 + t7) + t8 + tA) >> shift; + blk[7 * step] = (int)( -t4 + t9 + tB) >> shift; } static void fic_idct_put(uint8_t *dst, int stride, int16_t *block) @@ -110,14 +114,15 @@ static void fic_idct_put(uint8_t *dst, int stride, int16_t *block) int16_t *ptr; ptr = block; - for (i = 0; i < 8; i++) { - fic_idct(ptr, 8, 13); + fic_idct(ptr++, 8, 13, (1 << 12) + (1 << 17)); + for (i = 1; i < 8; i++) { + fic_idct(ptr, 8, 13, 1 << 12); ptr++; } ptr = block; for (i = 0; i < 8; i++) { - fic_idct(ptr, 1, 20); + fic_idct(ptr, 1, 20, 0); ptr += 8; } @@ -129,29 +134,30 @@ static void fic_idct_put(uint8_t *dst, int stride, int16_t *block) ptr += 8; } } -static int fic_decode_block(FICContext *ctx, BitstreamContext *bc, - uint8_t *dst, int stride, int16_t *block) +static int fic_decode_block(FICContext *ctx, GetBitContext *gb, + uint8_t *dst, int stride, int16_t *block, int *is_p) { int i, num_coeff; /* Is it a skip block? */ - if (bitstream_read_bit(bc)) { - /* This is a P-frame. */ - ctx->frame->key_frame = 0; - ctx->frame->pict_type = AV_PICTURE_TYPE_P; - + if (get_bits1(gb)) { + *is_p = 1; return 0; } memset(block, 0, sizeof(*block) * 64); - num_coeff = bitstream_read(bc, 7); + num_coeff = get_bits(gb, 7); if (num_coeff > 64) return AVERROR_INVALIDDATA; - for (i = 0; i < num_coeff; i++) - block[ff_zigzag_direct[i]] = get_se_golomb(bc) * + for (i = 0; i < num_coeff; i++) { + int v = get_se_golomb(gb); + if (v < -2048 || v > 2048) + return AVERROR_INVALIDDATA; + block[ff_zigzag_direct[i]] = v * ctx->qmat[ff_zigzag_direct[i]]; + } fic_idct_put(dst, stride, block); @@ -162,14 +168,14 @@ static int fic_decode_slice(AVCodecContext *avctx, void *tdata) { FICContext *ctx = avctx->priv_data; FICThreadContext *tctx = tdata; - BitstreamContext bc; + GetBitContext gb; uint8_t *src = tctx->src; int slice_h = tctx->slice_h; int src_size = tctx->src_size; int y_off = tctx->y_off; int x, y, p; - bitstream_init8(&bc, src, src_size); + init_get_bits(&gb, src, src_size * 8); for (p = 0; p < 3; p++) { int stride = ctx->frame->linesize[p]; @@ -179,7 +185,8 @@ static int fic_decode_slice(AVCodecContext *avctx, void *tdata) for (x = 0; x < (ctx->aligned_width >> !!p); x += 8) { int ret; - if ((ret = fic_decode_block(ctx, &bc, dst + x, stride, tctx->block)) != 0) + if ((ret = fic_decode_block(ctx, &gb, dst + x, stride, + tctx->block, &tctx->p_frame)) != 0) return ret; } @@ -263,13 +270,11 @@ static int fic_decode_frame(AVCodecContext *avctx, void *data, int msize; int tsize; int cur_x, cur_y; - int skip_cursor = 0; + int skip_cursor = ctx->skip_cursor; uint8_t *sdata; - if ((ret = ff_reget_buffer(avctx, ctx->frame)) < 0) { - av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); + if ((ret = ff_reget_buffer(avctx, ctx->frame)) < 0) return ret; - } /* Header + at least one slice (4) */ if (avpkt->size < FIC_HEADER_SIZE + 4) { @@ -282,8 +287,13 @@ static int fic_decode_frame(AVCodecContext *avctx, void *data, av_log(avctx, AV_LOG_WARNING, "Invalid FIC Header.\n"); /* Is it a skip frame? */ - if (src[17]) + if (src[17]) { + if (!ctx->final_frame) { + av_log(avctx, AV_LOG_WARNING, "Initial frame is skipped\n"); + return AVERROR_INVALIDDATA; + } goto skip; + } nslices = src[13]; if (!nslices) { @@ -303,7 +313,10 @@ static int fic_decode_frame(AVCodecContext *avctx, void *data, return AVERROR_INVALIDDATA; } - if (tsize < 32) { + if (!tsize || !AV_RL16(src + 37) || !AV_RL16(src + 39)) + skip_cursor = 1; + + if (!skip_cursor && tsize < 32) { av_log(avctx, AV_LOG_WARNING, "Cursor data too small. Skipping cursor.\n"); skip_cursor = 1; @@ -312,19 +325,23 @@ static int fic_decode_frame(AVCodecContext *avctx, void *data, /* Cursor position. */ cur_x = AV_RL16(src + 33); cur_y = AV_RL16(src + 35); - if (cur_x > avctx->width || cur_y > avctx->height) { - av_log(avctx, AV_LOG_WARNING, - "Invalid cursor position: (%d,%d). Skipping cusor.\n", + if (!skip_cursor && (cur_x > avctx->width || cur_y > avctx->height)) { + av_log(avctx, AV_LOG_DEBUG, + "Invalid cursor position: (%d,%d). Skipping cursor.\n", cur_x, cur_y); skip_cursor = 1; } - if (AV_RL16(src + 37) != 32 || AV_RL16(src + 39) != 32) { + if (!skip_cursor && (AV_RL16(src + 37) != 32 || AV_RL16(src + 39) != 32)) { av_log(avctx, AV_LOG_WARNING, "Invalid cursor size. Skipping cursor.\n"); skip_cursor = 1; } + if (!skip_cursor && avpkt->size < CURSOR_OFFSET + sizeof(ctx->cursor_buf)) { + skip_cursor = 1; + } + /* Slice height for all but the last slice. */ ctx->slice_h = 16 * (ctx->aligned_height >> 4) / nslices; if (ctx->slice_h % 16) @@ -339,15 +356,6 @@ static int fic_decode_frame(AVCodecContext *avctx, void *data, return AVERROR_INVALIDDATA; } - /* - * Set the frametype to I initially. It will be set to P if the frame - * has any dependencies (skip blocks). There will be a race condition - * inside the slice decode function to set these, but we do not care. - * since they will only ever be set to 0/P. - */ - ctx->frame->key_frame = 1; - ctx->frame->pict_type = AV_PICTURE_TYPE_I; - /* Allocate slice data. */ av_fast_malloc(&ctx->slice_data, &ctx->slice_data_size, nslices * sizeof(ctx->slice_data[0])); @@ -389,6 +397,15 @@ static int fic_decode_frame(AVCodecContext *avctx, void *data, NULL, nslices, sizeof(ctx->slice_data[0]))) < 0) return ret; + ctx->frame->key_frame = 1; + ctx->frame->pict_type = AV_PICTURE_TYPE_I; + for (slice = 0; slice < nslices; slice++) { + if (ctx->slice_data[slice].p_frame) { + ctx->frame->key_frame = 0; + ctx->frame->pict_type = AV_PICTURE_TYPE_P; + break; + } + } av_frame_free(&ctx->final_frame); ctx->final_frame = av_frame_clone(ctx->frame); if (!ctx->final_frame) { @@ -404,7 +421,7 @@ static int fic_decode_frame(AVCodecContext *avctx, void *data, /* Draw cursor. */ if (!skip_cursor) { - memcpy(ctx->cursor_buf, src + 59, 32 * 32 * 4); + memcpy(ctx->cursor_buf, src + CURSOR_OFFSET, sizeof(ctx->cursor_buf)); fic_draw_cursor(avctx, cur_x, cur_y); } @@ -446,6 +463,18 @@ static av_cold int fic_decode_init(AVCodecContext *avctx) return 0; } +static const AVOption options[] = { +{ "skip_cursor", "skip the cursor", offsetof(FICContext, skip_cursor), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM }, +{ NULL }, +}; + +static const AVClass fic_decoder_class = { + .class_name = "FIC decoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVCodec ff_fic_decoder = { .name = "fic", .long_name = NULL_IF_CONFIG_SMALL("Mirillis FIC"), @@ -456,4 +485,5 @@ AVCodec ff_fic_decoder = { .decode = fic_decode_frame, .close = fic_decode_close, .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_SLICE_THREADS, + .priv_class = &fic_decoder_class, }; |