summaryrefslogtreecommitdiff
path: root/libavcodec/huffyuvdec.c
diff options
context:
space:
mode:
authorPaul B Mahol <onemda@gmail.com>2018-08-22 22:11:42 +0200
committerPaul B Mahol <onemda@gmail.com>2018-12-31 15:41:23 +0100
commit41c1643d75860208d6debb8cb85d3edbd9457bd3 (patch)
treefc759687c5020142afa6d8907958ecedd8fa0b99 /libavcodec/huffyuvdec.c
parent8a8cce078c18050f0905a85997d80bb5c929fa00 (diff)
downloadffmpeg-41c1643d75860208d6debb8cb85d3edbd9457bd3.tar.gz
avcodec: add HYMT decoder
Diffstat (limited to 'libavcodec/huffyuvdec.c')
-rw-r--r--libavcodec/huffyuvdec.c174
1 files changed, 117 insertions, 57 deletions
diff --git a/libavcodec/huffyuvdec.c b/libavcodec/huffyuvdec.c
index 66357bfb40..4e00692631 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 */