From 41c1643d75860208d6debb8cb85d3edbd9457bd3 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Wed, 22 Aug 2018 22:11:42 +0200 Subject: [PATCH] avcodec: add HYMT decoder --- Changelog | 1 + libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/avcodec.h | 1 + libavcodec/codec_desc.c | 7 ++ libavcodec/huffyuvdec.c | 174 +++++++++++++++++++++++++++------------- libavcodec/version.h | 4 +- libavformat/riff.c | 1 + 8 files changed, 131 insertions(+), 59 deletions(-) diff --git a/Changelog b/Changelog index 4945efbba0a..f135fa56b6a 100644 --- a/Changelog +++ b/Changelog @@ -12,6 +12,7 @@ version : - PCM-DVD encoder - GIF parser - vividas demuxer +- hymt decoder version 4.1: diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 08f89ae0b20..99799ceed22 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -383,6 +383,7 @@ OBJS-$(CONFIG_HQ_HQA_DECODER) += hq_hqa.o hq_hqadata.o hq_hqadsp.o \ OBJS-$(CONFIG_HQX_DECODER) += hqx.o hqxvlc.o hqxdsp.o canopus.o OBJS-$(CONFIG_HUFFYUV_DECODER) += huffyuv.o huffyuvdec.o OBJS-$(CONFIG_HUFFYUV_ENCODER) += huffyuv.o huffyuvenc.o +OBJS-$(CONFIG_HYMT_DECODER) += huffyuv.o huffyuvdec.o OBJS-$(CONFIG_IDCIN_DECODER) += idcinvideo.o OBJS-$(CONFIG_IDF_DECODER) += bintext.o cga_data.o OBJS-$(CONFIG_IFF_ILBM_DECODER) += iff.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index d70646e91af..4755af71b27 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -152,6 +152,7 @@ extern AVCodec ff_hq_hqa_decoder; extern AVCodec ff_hqx_decoder; extern AVCodec ff_huffyuv_encoder; extern AVCodec ff_huffyuv_decoder; +extern AVCodec ff_hymt_decoder; extern AVCodec ff_idcin_decoder; extern AVCodec ff_iff_ilbm_decoder; extern AVCodec ff_imm4_decoder; diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index fd7f60bf4a6..92567ec6d0b 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -452,6 +452,7 @@ enum AVCodecID { AV_CODEC_ID_MWSC, AV_CODEC_ID_WCMV, AV_CODEC_ID_RASC, + AV_CODEC_ID_HYMT, /* various PCM "codecs" */ AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 73f343ce242..2363a532837 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -1691,6 +1691,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("RemotelyAnywhere Screen Capture"), .props = AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_HYMT, + .type = AVMEDIA_TYPE_VIDEO, + .name = "hymt", + .long_name = NULL_IF_CONFIG_SMALL("HuffYUV MT"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, /* various PCM "codecs" */ { diff --git a/libavcodec/huffyuvdec.c b/libavcodec/huffyuvdec.c index 66357bfb403..4e00692631e 100644 --- a/libavcodec/huffyuvdec.c +++ b/libavcodec/huffyuvdec.c @@ -905,54 +905,23 @@ static void add_median_prediction(HYuvContext *s, uint8_t *dst, const uint8_t *s s->hdsp.add_hfyu_median_pred_int16((uint16_t *)dst, (const uint16_t *)src, (const uint16_t *)diff, s->n-1, w, left, left_top); } } -static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, - AVPacket *avpkt) + +static int decode_slice(AVCodecContext *avctx, AVFrame *p, int height, + int buf_size, int y_offset, int table_size) { - const uint8_t *buf = avpkt->data; - int buf_size = avpkt->size; HYuvContext *s = avctx->priv_data; + int fake_ystride, fake_ustride, fake_vstride; const int width = s->width; const int width2 = s->width >> 1; - const int height = s->height; - int fake_ystride, fake_ustride, fake_vstride; - ThreadFrame frame = { .f = data }; - AVFrame *const p = data; - int table_size = 0, ret; - - if (buf_size < (width * height + 7)/8) - return AVERROR_INVALIDDATA; - - av_fast_padded_malloc(&s->bitstream_buffer, - &s->bitstream_buffer_size, - buf_size); - if (!s->bitstream_buffer) - return AVERROR(ENOMEM); - - s->bdsp.bswap_buf((uint32_t *) s->bitstream_buffer, - (const uint32_t *) buf, buf_size / 4); - - if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0) - return ret; - - if (s->context) { - table_size = read_huffman_tables(s, s->bitstream_buffer, buf_size); - if (table_size < 0) - return table_size; - } - - if ((unsigned) (buf_size - table_size) >= INT_MAX / 8) - return AVERROR_INVALIDDATA; + int ret; - if ((ret = init_get_bits(&s->gb, s->bitstream_buffer + table_size, - (buf_size - table_size) * 8)) < 0) + if ((ret = init_get_bits8(&s->gb, s->bitstream_buffer + table_size, buf_size - table_size)) < 0) return ret; fake_ystride = s->interlaced ? p->linesize[0] * 2 : p->linesize[0]; fake_ustride = s->interlaced ? p->linesize[1] * 2 : p->linesize[1]; fake_vstride = s->interlaced ? p->linesize[2] * 2 : p->linesize[2]; - s->last_slice_end = 0; - if (s->version > 2) { int plane; for(plane = 0; plane < 1 + 2*s->chroma + s->alpha; plane++) { @@ -1034,31 +1003,31 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, return AVERROR_PATCHWELCOME; } else { leftv = - p->data[2][0] = get_bits(&s->gb, 8); + p->data[2][0 + y_offset * p->linesize[2]] = get_bits(&s->gb, 8); lefty = - p->data[0][1] = get_bits(&s->gb, 8); + p->data[0][1 + y_offset * p->linesize[0]] = get_bits(&s->gb, 8); leftu = - p->data[1][0] = get_bits(&s->gb, 8); - p->data[0][0] = get_bits(&s->gb, 8); + p->data[1][0 + y_offset * p->linesize[1]] = get_bits(&s->gb, 8); + p->data[0][0 + y_offset * p->linesize[0]] = get_bits(&s->gb, 8); switch (s->predictor) { case LEFT: case PLANE: decode_422_bitstream(s, width - 2); - lefty = s->llviddsp.add_left_pred(p->data[0] + 2, s->temp[0], + lefty = s->llviddsp.add_left_pred(p->data[0] + p->linesize[0] * y_offset + 2, s->temp[0], width - 2, lefty); if (!(s->flags & AV_CODEC_FLAG_GRAY)) { - leftu = s->llviddsp.add_left_pred(p->data[1] + 1, s->temp[1], width2 - 1, leftu); - leftv = s->llviddsp.add_left_pred(p->data[2] + 1, s->temp[2], width2 - 1, leftv); + leftu = s->llviddsp.add_left_pred(p->data[1] + p->linesize[1] * y_offset + 1, s->temp[1], width2 - 1, leftu); + leftv = s->llviddsp.add_left_pred(p->data[2] + p->linesize[2] * y_offset + 1, s->temp[2], width2 - 1, leftv); } - for (cy = y = 1; y < s->height; y++, cy++) { + for (cy = y = 1; y < height; y++, cy++) { uint8_t *ydst, *udst, *vdst; if (s->bitstream_bpp == 12) { decode_gray_bitstream(s, width); - ydst = p->data[0] + p->linesize[0] * y; + ydst = p->data[0] + p->linesize[0] * (y + y_offset); lefty = s->llviddsp.add_left_pred(ydst, s->temp[0], width, lefty); @@ -1067,15 +1036,15 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, s->llviddsp.add_bytes(ydst, ydst - fake_ystride, width); } y++; - if (y >= s->height) + if (y >= height) break; } draw_slice(s, p, y); - ydst = p->data[0] + p->linesize[0] * y; - udst = p->data[1] + p->linesize[1] * cy; - vdst = p->data[2] + p->linesize[2] * cy; + ydst = p->data[0] + p->linesize[0] * (y + y_offset); + udst = p->data[1] + p->linesize[1] * (cy + y_offset); + vdst = p->data[2] + p->linesize[2] * (cy + y_offset); decode_422_bitstream(s, width); lefty = s->llviddsp.add_left_pred(ydst, s->temp[0], @@ -1185,7 +1154,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, } else { int y; uint8_t left[4]; - const int last_line = (height - 1) * p->linesize[0]; + const int last_line = (y_offset + height - 1) * p->linesize[0]; if (s->bitstream_bpp == 32) { left[A] = p->data[0][last_line + A] = get_bits(&s->gb, 8); @@ -1208,17 +1177,17 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, s->hdsp.add_hfyu_left_pred_bgr32(p->data[0] + last_line + 4, s->temp[0], width - 1, left); - for (y = s->height - 2; y >= 0; y--) { // Yes it is stored upside down. + for (y = height - 2; y >= 0; y--) { // Yes it is stored upside down. decode_bgr_bitstream(s, width); - s->hdsp.add_hfyu_left_pred_bgr32(p->data[0] + p->linesize[0] * y, + s->hdsp.add_hfyu_left_pred_bgr32(p->data[0] + p->linesize[0] * (y + y_offset), s->temp[0], width, left); if (s->predictor == PLANE) { if (s->bitstream_bpp != 32) left[A] = 0; - if (y < s->height - 1 - s->interlaced) { - s->llviddsp.add_bytes(p->data[0] + p->linesize[0] * y, - p->data[0] + p->linesize[0] * y + + if (y < height - 1 - s->interlaced) { + s->llviddsp.add_bytes(p->data[0] + p->linesize[0] * (y + y_offset), + p->data[0] + p->linesize[0] * (y + y_offset) + fake_ystride, 4 * width); } } @@ -1236,7 +1205,82 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, return AVERROR_PATCHWELCOME; } } - emms_c(); + + return 0; +} + +static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, + AVPacket *avpkt) +{ + const uint8_t *buf = avpkt->data; + int buf_size = avpkt->size; + HYuvContext *s = avctx->priv_data; + const int width = s->width; + const int height = s->height; + ThreadFrame frame = { .f = data }; + AVFrame *const p = data; + int slice, table_size = 0, ret, nb_slices; + unsigned slices_info_offset; + int slice_height; + + if (buf_size < (width * height + 7)/8) + return AVERROR_INVALIDDATA; + + av_fast_padded_malloc(&s->bitstream_buffer, + &s->bitstream_buffer_size, + buf_size); + if (!s->bitstream_buffer) + return AVERROR(ENOMEM); + + s->bdsp.bswap_buf((uint32_t *) s->bitstream_buffer, + (const uint32_t *) buf, buf_size / 4); + + if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0) + return ret; + + if (s->context) { + table_size = read_huffman_tables(s, s->bitstream_buffer, buf_size); + if (table_size < 0) + return table_size; + } + + if ((unsigned) (buf_size - table_size) >= INT_MAX / 8) + return AVERROR_INVALIDDATA; + + s->last_slice_end = 0; + + if (avctx->codec_id == AV_CODEC_ID_HYMT && + (buf_size > 32 && AV_RL32(avpkt->data + buf_size - 16) == 0)) { + slices_info_offset = AV_RL32(avpkt->data + buf_size - 4); + slice_height = AV_RL32(avpkt->data + buf_size - 8); + nb_slices = AV_RL32(avpkt->data + buf_size - 12); + if (nb_slices * 8LL + slices_info_offset > buf_size - 16) + return AVERROR_INVALIDDATA; + } else { + slice_height = height; + nb_slices = 1; + } + + for (slice = 0; slice < nb_slices; slice++) { + int y_offset, slice_offset, slice_size; + + if (nb_slices > 1) { + slice_offset = AV_RL32(avpkt->data + slices_info_offset + slice * 8); + slice_size = AV_RL32(avpkt->data + slices_info_offset + slice * 8 + 4); + y_offset = height - (slice + 1) * slice_height; + s->bdsp.bswap_buf((uint32_t *)s->bitstream_buffer, + (const uint32_t *)(buf + slice_offset), slice_size / 4); + } else { + y_offset = 0; + slice_offset = 0; + slice_size = buf_size; + } + + ret = decode_slice(avctx, p, slice_height, slice_size, y_offset, table_size); + emms_c(); + if (ret < 0) + return ret; + } *got_frame = 1; @@ -1272,3 +1316,19 @@ AVCodec ff_ffvhuff_decoder = { .init_thread_copy = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy), }; #endif /* CONFIG_FFVHUFF_DECODER */ + +#if CONFIG_HYMT_DECODER +AVCodec ff_hymt_decoder = { + .name = "hymt", + .long_name = NULL_IF_CONFIG_SMALL("HuffYUV MT"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_HYMT, + .priv_data_size = sizeof(HYuvContext), + .init = decode_init, + .close = decode_end, + .decode = decode_frame, + .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DRAW_HORIZ_BAND | + AV_CODEC_CAP_FRAME_THREADS, + .init_thread_copy = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy), +}; +#endif /* CONFIG_HYMT_DECODER */ diff --git a/libavcodec/version.h b/libavcodec/version.h index 3c61e0c4ca4..ed56a1ece52 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -28,8 +28,8 @@ #include "libavutil/version.h" #define LIBAVCODEC_VERSION_MAJOR 58 -#define LIBAVCODEC_VERSION_MINOR 42 -#define LIBAVCODEC_VERSION_MICRO 104 +#define LIBAVCODEC_VERSION_MINOR 43 +#define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ LIBAVCODEC_VERSION_MINOR, \ diff --git a/libavformat/riff.c b/libavformat/riff.c index 3907e1a9f38..d5a509c8b91 100644 --- a/libavformat/riff.c +++ b/libavformat/riff.c @@ -475,6 +475,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_MWSC, MKTAG('M', 'W', 'S', 'C') }, { AV_CODEC_ID_WCMV, MKTAG('W', 'C', 'M', 'V') }, { AV_CODEC_ID_RASC, MKTAG('R', 'A', 'S', 'C') }, + { AV_CODEC_ID_HYMT, MKTAG('H', 'Y', 'M', 'T') }, { AV_CODEC_ID_NONE, 0 } }; -- 2.39.5