diff options
author | Paul B Mahol <onemda@gmail.com> | 2016-05-10 23:48:50 +0200 |
---|---|---|
committer | Paul B Mahol <onemda@gmail.com> | 2016-05-13 00:24:48 +0200 |
commit | cb928fc448f9566e6f6c28d53fa4c2388e732a2b (patch) | |
tree | 6d737ef94f98f055cdc4aa6b2cc3af3618bc609a | |
parent | 97946b20b6d8c8746ca41490534d7ecceaab799b (diff) | |
download | ffmpeg-cb928fc448f9566e6f6c28d53fa4c2388e732a2b.tar.gz |
lavc: add IFF ANIM decoder
Signed-off-by: Paul B Mahol <onemda@gmail.com>
-rw-r--r-- | Changelog | 1 | ||||
-rw-r--r-- | libavcodec/codec_desc.c | 2 | ||||
-rw-r--r-- | libavcodec/iff.c | 825 | ||||
-rw-r--r-- | libavformat/iff.c | 88 |
4 files changed, 819 insertions, 97 deletions
@@ -33,6 +33,7 @@ version <next>: - VAAPI-accelerated H.264/HEVC/MJPEG encoding - DTS Express (LBR) decoder - Generic OpenMAX IL encoder with support for Raspberry Pi +- IFF ANIM demuxer & decoder version 3.0: - Common Encryption (CENC) MP4 encoding and decoding support diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index c582b490c0..57bd4ba5de 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -887,7 +887,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .id = AV_CODEC_ID_IFF_ILBM, .type = AVMEDIA_TYPE_VIDEO, .name = "iff_ilbm", - .long_name = NULL_IF_CONFIG_SMALL("IFF ILBM"), + .long_name = NULL_IF_CONFIG_SMALL("IFF ACBM/ANIM/DEEP/ILBM/PBM"), .props = AV_CODEC_PROP_LOSSY, }, { diff --git a/libavcodec/iff.c b/libavcodec/iff.c index 49df17ccf8..806521023d 100644 --- a/libavcodec/iff.c +++ b/libavcodec/iff.c @@ -1,7 +1,8 @@ /* - * IFF ACBM/DEEP/ILBM/PBM bitmap decoder + * IFF ACBM/ANIM/DEEP/ILBM/PBM bitmap decoder * Copyright (c) 2010 Peter Ross <pross@xvid.org> * Copyright (c) 2010 Sebastian Vater <cdgs.basty@googlemail.com> + * Copyright (c) 2016 Paul B Mahol * * This file is part of FFmpeg. * @@ -22,7 +23,7 @@ /** * @file - * IFF ACBM/DEEP/ILBM/PBM bitmap decoder + * IFF ACBM/ANIM/DEEP/ILBM/PBM bitmap decoder */ #include <stdint.h> @@ -30,8 +31,8 @@ #include "libavutil/imgutils.h" #include "bytestream.h" #include "avcodec.h" -#include "get_bits.h" #include "internal.h" +#include "mathops.h" // TODO: masking bits typedef enum { @@ -50,6 +51,7 @@ typedef struct IffContext { uint32_t *mask_buf; ///< temporary buffer for palette indices uint32_t *mask_palbuf; ///< masking palette table unsigned compression; ///< delta compression method used + unsigned is_short; ///< short compression method used unsigned bpp; ///< bits per plane to decode (differs from bits_per_coded_sample if HAM) unsigned ham; ///< 0 if non-HAM or number of hold bits (6 for bpp > 6, 4 otherwise) unsigned flags; ///< 1 for EHB, 0 is no extra half darkening @@ -57,6 +59,11 @@ typedef struct IffContext { unsigned masking; ///< TODO: masking method used int init; // 1 if buffer and palette data already initialized, 0 otherwise int16_t tvdc[16]; ///< TVDC lookup table + GetByteContext gb; + uint8_t *video[2]; + unsigned video_size; + uint32_t *pal[2]; + int first; } IffContext; #define LUT8_PART(plane, v) \ @@ -189,10 +196,11 @@ static int cmap_read_palette(AVCodecContext *avctx, uint32_t *pal) * @return >= 0 in case of success, a negative error code otherwise */ static int extract_header(AVCodecContext *const avctx, - const AVPacket *const avpkt) { - const uint8_t *buf; - unsigned buf_size; + const AVPacket *const avpkt) +{ IffContext *s = avctx->priv_data; + const uint8_t *buf; + unsigned buf_size = 0; int i, palette_size; if (avctx->extradata_size < 2) { @@ -201,20 +209,51 @@ static int extract_header(AVCodecContext *const avctx, } palette_size = avctx->extradata_size - AV_RB16(avctx->extradata); - if (avpkt) { - int image_size; - if (avpkt->size < 2) - return AVERROR_INVALIDDATA; - image_size = avpkt->size - AV_RB16(avpkt->data); - buf = avpkt->data; - buf_size = bytestream_get_be16(&buf); - if (buf_size <= 1 || image_size <= 1) { - av_log(avctx, AV_LOG_ERROR, - "Invalid image size received: %u -> image data offset: %d\n", - buf_size, image_size); - return AVERROR_INVALIDDATA; + if (avpkt && avctx->codec_tag == MKTAG('A', 'N', 'I', 'M')) { + uint32_t chunk_id; + uint64_t data_size; + GetByteContext *gb = &s->gb; + + bytestream2_skip(gb, 4); + while (bytestream2_get_bytes_left(gb) >= 1) { + chunk_id = bytestream2_get_le32(gb); + data_size = bytestream2_get_be32(gb); + + if (chunk_id == MKTAG('B', 'M', 'H', 'D')) { + bytestream2_skip(gb, data_size + (data_size & 1)); + } else if (chunk_id == MKTAG('A', 'N', 'H', 'D')) { + if (data_size < 40) + return AVERROR_INVALIDDATA; + + s->compression = (bytestream2_get_byte(gb) << 8) | (s->compression & 0xFF); + bytestream2_skip(gb, 19); + s->is_short = !(bytestream2_get_be32(gb) & 1); + data_size -= 24; + bytestream2_skip(gb, data_size + (data_size & 1)); + } else if (chunk_id == MKTAG('D', 'L', 'T', 'A') || + chunk_id == MKTAG('B', 'O', 'D', 'Y')) { + if (chunk_id == MKTAG('B','O','D','Y')) + s->compression &= 0xFF; + break; + } else if (chunk_id == MKTAG('C', 'M', 'A', 'P')) { + int count = data_size / 3; + uint32_t *pal = s->pal[0]; + + if (count > 256) + return AVERROR_INVALIDDATA; + if (s->ham) { + for (i = 0; i < count; i++) + pal[i] = 0xFF000000 | bytestream2_get_le24(gb); + } else { + for (i = 0; i < count; i++) + pal[i] = 0xFF000000 | bytestream2_get_be24(gb); + } + bytestream2_skip(gb, data_size & 1); + } else { + bytestream2_skip(gb, data_size + (data_size&1)); + } } - } else { + } else if (!avpkt) { buf = avctx->extradata; buf_size = bytestream_get_be16(&buf); if (buf_size <= 1 || palette_size < 0) { @@ -323,10 +362,13 @@ static int extract_header(AVCodecContext *const avctx, static av_cold int decode_end(AVCodecContext *avctx) { IffContext *s = avctx->priv_data; - av_frame_free(&s->frame); av_freep(&s->planebuf); av_freep(&s->ham_buf); av_freep(&s->ham_palbuf); + av_freep(&s->video[0]); + av_freep(&s->video[1]); + av_freep(&s->pal[0]); + av_freep(&s->pal[1]); return 0; } @@ -371,10 +413,16 @@ static av_cold int decode_init(AVCodecContext *avctx) return AVERROR(ENOMEM); s->bpp = avctx->bits_per_coded_sample; - s->frame = av_frame_alloc(); - if (!s->frame) { - decode_end(avctx); - return AVERROR(ENOMEM); + + if (avctx->codec_tag == MKTAG('A', 'N', 'I', 'M')) { + s->video_size = FFALIGN(avctx->width, 2) * avctx->height * s->bpp; + s->video[0] = av_calloc(FFALIGN(avctx->width, 2) * avctx->height, s->bpp); + s->video[1] = av_calloc(FFALIGN(avctx->width, 2) * avctx->height, s->bpp); + s->pal[0] = av_calloc(256, sizeof(*s->pal[0])); + s->pal[1] = av_calloc(256, sizeof(*s->pal[1])); + if (!s->video[0] || !s->video[1] || !s->pal[0] || !s->pal[1]) + return AVERROR(ENOMEM); + s->first = 1; } if ((err = extract_header(avctx, NULL)) < 0) @@ -480,20 +528,18 @@ static void lookup_pal_indicies(uint32_t *dst, const uint32_t *buf, * @return number of consumed bytes in byterun1 compressed bitstream */ static int decode_byterun(uint8_t *dst, int dst_size, - const uint8_t *buf, const uint8_t *const buf_end) + GetByteContext *gb) { - const uint8_t *const buf_start = buf; unsigned x; - for (x = 0; x < dst_size && buf < buf_end;) { + for (x = 0; x < dst_size && bytestream2_get_bytes_left(gb) > 0;) { unsigned length; - const int8_t value = *buf++; + const int8_t value = bytestream2_get_byte(gb); if (value >= 0) { - length = FFMIN3(value + 1, dst_size - x, buf_end - buf); - memcpy(dst + x, buf, length); - buf += length; + length = FFMIN3(value + 1, dst_size - x, bytestream2_get_bytes_left(gb)); + bytestream2_get_buffer(gb, dst + x, length); } else if (value > -128) { length = FFMIN(-value + 1, dst_size - x); - memset(dst + x, *buf++, length); + memset(dst + x, bytestream2_get_byte(gb), length); } else { // noop continue; } @@ -503,7 +549,7 @@ static int decode_byterun(uint8_t *dst, int dst_size, av_log(NULL, AV_LOG_WARNING, "decode_byterun ended before plane size\n"); memset(dst+x, 0, dst_size - x); } - return buf - buf_start; + return bytestream2_tell(gb); } #define DECODE_RGBX_COMMON(type) \ @@ -660,10 +706,525 @@ static void decode_deep_tvdc32(uint8_t *dst, const uint8_t *src, int src_size, i } } +static void decode_byte_vertical_delta(uint8_t *dst, + const uint8_t *buf, const uint8_t *buf_end, + int w, int bpp, int dst_size) +{ + int ncolumns = ((w + 15) / 16) * 2; + int dstpitch = ncolumns * bpp; + unsigned ofsdst, ofssrc, opcode, x; + GetByteContext ptrs, gb; + PutByteContext pb; + int i, j, k; + + bytestream2_init(&ptrs, buf, buf_end - buf); + bytestream2_init_writer(&pb, dst, dst_size); + + for (k = 0; k < bpp; k++) { + ofssrc = bytestream2_get_be32(&ptrs); + + if (!ofssrc) + continue; + + if (ofssrc >= buf_end - buf) + continue; + + bytestream2_init(&gb, buf + ofssrc, buf_end - (buf + ofssrc)); + for (j = 0; j < ncolumns; j++) { + ofsdst = j + k * ncolumns; + + i = bytestream2_get_byte(&gb); + while (i > 0) { + opcode = bytestream2_get_byte(&gb); + + if (opcode == 0) { + opcode = bytestream2_get_byte(&gb); + x = bytestream2_get_byte(&gb); + + while (opcode) { + bytestream2_seek_p(&pb, ofsdst, SEEK_SET); + bytestream2_put_byte(&pb, x); + ofsdst += dstpitch; + opcode--; + } + } else if (opcode < 0x80) { + ofsdst += opcode * dstpitch; + } else { + opcode &= 0x7f; + + while (opcode) { + bytestream2_seek_p(&pb, ofsdst, SEEK_SET); + bytestream2_put_byte(&pb, bytestream2_get_byte(&gb)); + ofsdst += dstpitch; + opcode--; + } + } + i--; + } + } + } +} + +static void decode_delta_j(uint8_t *dst, + const uint8_t *buf, const uint8_t *buf_end, + int w, int h, int bpp, int dst_size) +{ + int32_t pitch; + uint8_t *end = dst + dst_size, *ptr; + uint32_t type, flag, cols, groups, rows, bytes; + uint32_t offset; + int planepitch_byte = (w + 7) / 8; + int planepitch = ((w + 15) / 16) * 2; + int kludge_j, b, g, r, d; + GetByteContext gb; + + pitch = planepitch * bpp; + kludge_j = w < 320 ? (320 - w) / 8 / 2 : 0; + + bytestream2_init(&gb, buf, buf_end - buf); + + while (bytestream2_get_bytes_left(&gb) >= 2) { + type = bytestream2_get_be16(&gb); + + switch (type) { + case 0: + return; + case 1: + flag = bytestream2_get_be16(&gb); + cols = bytestream2_get_be16(&gb); + groups = bytestream2_get_be16(&gb); + + for (g = 0; g < groups; g++) { + offset = bytestream2_get_be16(&gb); + + if (kludge_j) + offset = ((offset / (320 / 8)) * pitch) + (offset % (320 / 8)) - kludge_j; + else + offset = ((offset / planepitch_byte) * pitch) + (offset % planepitch_byte); + + ptr = dst + offset; + if (ptr >= end) + return; + + for (b = 0; b < cols; b++) { + for (d = 0; d < bpp; d++) { + uint8_t value = bytestream2_get_byte(&gb); + + if (flag) + ptr[0] ^= value; + else + ptr[0] = value; + + ptr += planepitch; + if (ptr >= end) + return; + } + } + if ((cols * bpp) & 1) + bytestream2_skip(&gb, 1); + } + break; + case 2: + flag = bytestream2_get_be16(&gb); + rows = bytestream2_get_be16(&gb); + bytes = bytestream2_get_be16(&gb); + groups = bytestream2_get_be16(&gb); + + for (g = 0; g < groups; g++) { + offset = bytestream2_get_be16(&gb); + + if (kludge_j) + offset = ((offset / (320 / 8)) * pitch) + (offset % (320/ 8)) - kludge_j; + else + offset = ((offset / planepitch_byte) * pitch) + (offset % planepitch_byte); + + for (r = 0; r < rows; r++) { + for (d = 0; d < bpp; d++) { + ptr = dst + offset + (r * pitch) + d * planepitch; + if (ptr >= end) + return; + + for (b = 0; b < bytes; b++) { + uint8_t value = bytestream2_get_byte(&gb); + + if (flag) + ptr[0] ^= value; + else + ptr[0] = value; + + ptr++; + if (ptr >= end) + return; + } + } + } + if ((rows * bytes * bpp) & 1) + bytestream2_skip(&gb, 1); + } + break; + default: + return; + } + } +} + +static void decode_short_vertical_delta(uint8_t *dst, + const uint8_t *buf, const uint8_t *buf_end, + int w, int bpp, int dst_size) +{ + int ncolumns = (w + 15) >> 4; + int dstpitch = ncolumns * bpp * 2; + unsigned ofsdst, ofssrc, ofsdata, opcode, x; + GetByteContext ptrs, gb, dptrs, dgb; + PutByteContext pb; + int i, j, k; + + if (buf_end - buf <= 64) + return; + + bytestream2_init(&ptrs, buf, buf_end - buf); + bytestream2_init(&dptrs, buf + 32, (buf_end - buf) - 32); + bytestream2_init_writer(&pb, dst, dst_size); + + for (k = 0; k < bpp; k++) { + ofssrc = bytestream2_get_be32(&ptrs); + ofsdata = bytestream2_get_be32(&dptrs); + + if (!ofssrc) + continue; + + if (ofssrc >= buf_end - buf) + return; + + if (ofsdata >= buf_end - buf) + return; + + bytestream2_init(&gb, buf + ofssrc, buf_end - (buf + ofssrc)); + bytestream2_init(&dgb, buf + ofsdata, buf_end - (buf + ofsdata)); + for (j = 0; j < ncolumns; j++) { + ofsdst = (j + k * ncolumns) * 2; + + i = bytestream2_get_byte(&gb); + while (i > 0) { + opcode = bytestream2_get_byte(&gb); + + if (opcode == 0) { + opcode = bytestream2_get_byte(&gb); + x = bytestream2_get_be16(&dgb); + + while (opcode) { + bytestream2_seek_p(&pb, ofsdst, SEEK_SET); + bytestream2_put_be16(&pb, x); + ofsdst += dstpitch; + opcode--; + } + } else if (opcode < 0x80) { + ofsdst += opcode * dstpitch; + } else { + opcode &= 0x7f; + + while (opcode) { + bytestream2_seek_p(&pb, ofsdst, SEEK_SET); + bytestream2_put_be16(&pb, bytestream2_get_be16(&dgb)); + ofsdst += dstpitch; + opcode--; + } + } + i--; + } + } + } +} + +static void decode_long_vertical_delta(uint8_t *dst, + const uint8_t *buf, const uint8_t *buf_end, + int w, int bpp, int dst_size) +{ + int ncolumns = (w + 31) >> 5; + int dstpitch = ((w + 15) / 16 * 2) * bpp; + unsigned ofsdst, ofssrc, ofsdata, opcode, x; + GetByteContext ptrs, gb, dptrs, dgb; + PutByteContext pb; + int i, j, k, h; + + if (buf_end - buf <= 64) + return; + + h = (((w + 15) / 16 * 2) != ((w + 31) / 32 * 4)) ? 1 : 0; + bytestream2_init(&ptrs, buf, buf_end - buf); + bytestream2_init(&dptrs, buf + 32, (buf_end - buf) - 32); + bytestream2_init_writer(&pb, dst, dst_size); + + for (k = 0; k < bpp; k++) { + ofssrc = bytestream2_get_be32(&ptrs); + ofsdata = bytestream2_get_be32(&dptrs); + + if (!ofssrc) + continue; + + if (ofssrc >= buf_end - buf) + return; + + if (ofsdata >= buf_end - buf) + return; + + bytestream2_init(&gb, buf + ofssrc, buf_end - (buf + ofssrc)); + bytestream2_init(&dgb, buf + ofsdata, buf_end - (buf + ofsdata)); + for (j = 0; j < ncolumns; j++) { + ofsdst = (j + k * ncolumns) * 4 - h * (2 * k); + + i = bytestream2_get_byte(&gb); + while (i > 0) { + opcode = bytestream2_get_byte(&gb); + + if (opcode == 0) { + opcode = bytestream2_get_byte(&gb); + if (h && (j == (ncolumns - 1))) { + x = bytestream2_get_be16(&dgb); + bytestream2_skip(&dgb, 2); + } else { + x = bytestream2_get_be32(&dgb); + } + + while (opcode) { + bytestream2_seek_p(&pb, ofsdst, SEEK_SET); + if (h && (j == (ncolumns - 1))) { + bytestream2_put_be16(&pb, x); + } else { + bytestream2_put_be32(&pb, x); + } + ofsdst += dstpitch; + opcode--; + } + } else if (opcode < 0x80) { + ofsdst += opcode * dstpitch; + } else { + opcode &= 0x7f; + + while (opcode) { + bytestream2_seek_p(&pb, ofsdst, SEEK_SET); + if (h && (j == (ncolumns - 1))) { + bytestream2_put_be16(&pb, bytestream2_get_be16(&dgb)); + bytestream2_skip(&dgb, 2); + } else { + bytestream2_put_be32(&pb, bytestream2_get_be32(&dgb)); + } + ofsdst += dstpitch; + opcode--; + } + } + i--; + } + } + } +} + +static void decode_short_vertical_delta2(uint8_t *dst, + const uint8_t *buf, const uint8_t *buf_end, + int w, int bpp, int dst_size) +{ + int ncolumns = (w + 15) >> 4; + int dstpitch = ncolumns * bpp * 2; + unsigned ofsdst, ofssrc, opcode, x; + GetByteContext ptrs, gb; + PutByteContext pb; + int i, j, k; + + bytestream2_init(&ptrs, buf, buf_end - buf); + bytestream2_init_writer(&pb, dst, dst_size); + + for (k = 0; k < bpp; k++) { + ofssrc = bytestream2_get_be32(&ptrs); + + if (!ofssrc) + continue; + + if (ofssrc >= buf_end - buf) + continue; + + bytestream2_init(&gb, buf + ofssrc, buf_end - (buf + ofssrc)); + for (j = 0; j < ncolumns; j++) { + ofsdst = (j + k * ncolumns) * 2; + + i = bytestream2_get_be16(&gb); + while (i > 0 && bytestream2_get_bytes_left(&gb) > 4) { + opcode = bytestream2_get_be16(&gb); + + if (opcode == 0) { + opcode = bytestream2_get_be16(&gb); + x = bytestream2_get_be16(&gb); + + while (opcode && bytestream2_get_bytes_left_p(&pb) > 1) { + bytestream2_seek_p(&pb, ofsdst, SEEK_SET); + bytestream2_put_be16(&pb, x); + ofsdst += dstpitch; + opcode--; + } + } else if (opcode < 0x8000) { + ofsdst += opcode * dstpitch; + } else { + opcode &= 0x7fff; + + while (opcode && bytestream2_get_bytes_left(&gb) > 1 && + bytestream2_get_bytes_left_p(&pb) > 1) { + bytestream2_seek_p(&pb, ofsdst, SEEK_SET); + bytestream2_put_be16(&pb, bytestream2_get_be16(&gb)); + ofsdst += dstpitch; + opcode--; + } + } + i--; + } + } + } +} + +static void decode_long_vertical_delta2(uint8_t *dst, + const uint8_t *buf, const uint8_t *buf_end, + int w, int bpp, int dst_size) +{ + int ncolumns = (w + 31) >> 5; + int dstpitch = ((w + 15) / 16 * 2) * bpp; + unsigned ofsdst, ofssrc, opcode, x; + unsigned skip = 0x80000000, mask = skip - 1; + GetByteContext ptrs, gb; + PutByteContext pb; + int i, j, k, h; + + h = (((w + 15) / 16 * 2) != ((w + 31) / 32 * 4)) ? 1 : 0; + bytestream2_init(&ptrs, buf, buf_end - buf); + bytestream2_init_writer(&pb, dst, dst_size); + + for (k = 0; k < bpp; k++) { + ofssrc = bytestream2_get_be32(&ptrs); + + if (!ofssrc) + continue; + + if (ofssrc >= buf_end - buf) + continue; + + bytestream2_init(&gb, buf + ofssrc, buf_end - (buf + ofssrc)); + for (j = 0; j < ncolumns; j++) { + ofsdst = (j + k * ncolumns) * 4 - h * (2 * k); + + if (h && (j == (ncolumns - 1))) { + skip = 0x8000; + mask = skip - 1; + } + + i = bytestream2_get_be32(&gb); + while (i > 0 && bytestream2_get_bytes_left(&gb) > 4) { + opcode = bytestream2_get_be32(&gb); + + if (opcode == 0) { + if (h && (j == ncolumns - 1)) { + opcode = bytestream2_get_be16(&gb); + x = bytestream2_get_be16(&gb); + } else { + opcode = bytestream2_get_be32(&gb); + x = bytestream2_get_be32(&gb); + } + + while (opcode && bytestream2_get_bytes_left_p(&pb) > 1) { + bytestream2_seek_p(&pb, ofsdst, SEEK_SET); + if (h && (j == ncolumns - 1)) + bytestream2_put_be16(&pb, x); + else + bytestream2_put_be32(&pb, x); + ofsdst += dstpitch; + opcode--; + } + } else if (opcode < skip) { + ofsdst += opcode * dstpitch; + } else { + opcode &= mask; + + while (opcode && bytestream2_get_bytes_left(&gb) > 1 && + bytestream2_get_bytes_left_p(&pb) > 1) { + bytestream2_seek_p(&pb, ofsdst, SEEK_SET); + if (h && (j == ncolumns - 1)) { + bytestream2_put_be16(&pb, bytestream2_get_be16(&gb)); + } else { + bytestream2_put_be32(&pb, bytestream2_get_be32(&gb)); + } + ofsdst += dstpitch; + opcode--; + } + } + i--; + } + } + } +} + +static void decode_delta_l(uint8_t *dst, + const uint8_t *buf, const uint8_t *buf_end, + int w, int flag, int bpp, int dst_size) +{ + GetByteContext off0, off1, dgb, ogb; + PutByteContext pb; + unsigned poff0, poff1; + int i, k, dstpitch; + int planepitch_byte = (w + 7) / 8; + int planepitch = ((w + 15) / 16) * 2; + int pitch = planepitch * bpp; + + if (buf_end - buf <= 64) + return; + + bytestream2_init(&off0, buf, buf_end - buf); + bytestream2_init(&off1, buf + 32, buf_end - (buf + 32)); + bytestream2_init_writer(&pb, dst, dst_size); + + dstpitch = flag ? (((w + 7) / 8) * bpp): 2; + + for (k = 0; k < bpp; k++) { + poff0 = bytestream2_get_be32(&off0); + poff1 = bytestream2_get_be32(&off1); + + if (!poff0) + continue; + + if (2LL * poff0 >= buf_end - buf) + return; + + if (2LL * poff1 >= buf_end - buf) + return; + + bytestream2_init(&dgb, buf + 2 * poff0, buf_end - (buf + 2 * poff0)); + bytestream2_init(&ogb, buf + 2 * poff1, buf_end - (buf + 2 * poff1)); + + while ((bytestream2_peek_be16(&ogb)) != 0xFFFF) { + uint16_t offset = bytestream2_get_be16(&ogb); + int16_t cnt = bytestream2_get_be16(&ogb); + uint16_t data; + + offset = ((2 * offset) / planepitch_byte) * pitch + ((2 * offset) % planepitch_byte) + k * planepitch; + if (cnt < 0) { + bytestream2_seek_p(&pb, offset, SEEK_SET); + cnt = -cnt; + data = bytestream2_get_be16(&dgb); + for (i = 0; i < cnt; i++) { + bytestream2_put_be16(&pb, data); + bytestream2_skip_p(&pb, dstpitch - 2); + } + } else { + bytestream2_seek_p(&pb, offset, SEEK_SET); + for (i = 0; i < cnt; i++) { + data = bytestream2_get_be16(&dgb); + bytestream2_put_be16(&pb, data); + bytestream2_skip_p(&pb, dstpitch - 2); + } + } + } + } +} + static int unsupported(AVCodecContext *avctx) { IffContext *s = avctx->priv_data; - avpriv_request_sample(avctx, "bitmap (compression %i, bpp %i, ham %i)", s->compression, s->bpp, s->ham); + avpriv_request_sample(avctx, "bitmap (compression 0x%0x, bpp %i, ham %i)", s->compression, s->bpp, s->ham); return AVERROR_INVALIDDATA; } @@ -672,23 +1233,30 @@ static int decode_frame(AVCodecContext *avctx, AVPacket *avpkt) { IffContext *s = avctx->priv_data; - const uint8_t *buf = avpkt->size >= 2 ? avpkt->data + AV_RB16(avpkt->data) : NULL; - const int buf_size = avpkt->size >= 2 ? avpkt->size - AV_RB16(avpkt->data) : 0; + AVFrame *frame = data; + const uint8_t *buf = avpkt->data; + int buf_size = avpkt->size; const uint8_t *buf_end = buf + buf_size; int y, plane, res; - GetByteContext gb; + GetByteContext *gb = &s->gb; const AVPixFmtDescriptor *desc; + bytestream2_init(gb, avpkt->data, avpkt->size); + if ((res = extract_header(avctx, avpkt)) < 0) return res; - if ((res = ff_reget_buffer(avctx, s->frame)) < 0) + + if ((res = ff_get_buffer(avctx, frame, 0)) < 0) return res; + s->frame = frame; + buf += bytestream2_tell(gb); + buf_size -= bytestream2_tell(gb); desc = av_pix_fmt_desc_get(avctx->pix_fmt); if (!s->init && avctx->bits_per_coded_sample <= 8 && avctx->pix_fmt == AV_PIX_FMT_PAL8) { - if ((res = cmap_read_palette(avctx, (uint32_t *)s->frame->data[1])) < 0) + if ((res = cmap_read_palette(avctx, (uint32_t *)frame->data[1])) < 0) return res; } else if (!s->init && avctx->bits_per_coded_sample <= 8 && avctx->pix_fmt == AV_PIX_FMT_RGB32) { @@ -697,22 +1265,33 @@ static int decode_frame(AVCodecContext *avctx, } s->init = 1; + if (s->compression <= 0xff && avctx->codec_tag == MKTAG('A', 'N', 'I', 'M')) { + if (avctx->pix_fmt == AV_PIX_FMT_PAL8) + memcpy(s->pal[0], s->frame->data[1], 256 * 4); + } + + if (s->compression > 0xff && s->first) { + memcpy(s->video[1], s->video[0], s->video_size); + memcpy(s->pal[1], s->pal[0], 256 * 4); + s->first = 0; + } + switch (s->compression) { - case 0: + case 0x0: if (avctx->codec_tag == MKTAG('A', 'C', 'B', 'M')) { if (avctx->pix_fmt == AV_PIX_FMT_PAL8 || avctx->pix_fmt == AV_PIX_FMT_GRAY8) { - memset(s->frame->data[0], 0, avctx->height * s->frame->linesize[0]); + memset(frame->data[0], 0, avctx->height * frame->linesize[0]); for (plane = 0; plane < s->bpp; plane++) { for (y = 0; y < avctx->height && buf < buf_end; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; decodeplane8(row, buf, FFMIN(s->planesize, buf_end - buf), plane); buf += s->planesize; } } } else if (s->ham) { // HAM to AV_PIX_FMT_BGR32 - memset(s->frame->data[0], 0, avctx->height * s->frame->linesize[0]); + memset(frame->data[0], 0, avctx->height * frame->linesize[0]); for (y = 0; y < avctx->height; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memset(s->ham_buf, 0, s->planesize * 8); for (plane = 0; plane < s->bpp; plane++) { const uint8_t * start = buf + (plane * avctx->height + y) * s->planesize; @@ -728,7 +1307,7 @@ static int decode_frame(AVCodecContext *avctx, int raw_width = avctx->width * (av_get_bits_per_pixel(desc) >> 3); int x; for (y = 0; y < avctx->height && buf < buf_end; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memcpy(row, buf, FFMIN(raw_width, buf_end - buf)); buf += raw_width; if (avctx->pix_fmt == AV_PIX_FMT_BGR32) { @@ -736,10 +1315,13 @@ static int decode_frame(AVCodecContext *avctx, row[4 * x + 3] = row[4 * x + 3] & 0xF0 | (row[4 * x + 3] >> 4); } } - } else if (avctx->codec_tag == MKTAG('I', 'L', 'B', 'M')) { // interleaved + } else if (avctx->codec_tag == MKTAG('I', 'L', 'B', 'M') || // interleaved + avctx->codec_tag == MKTAG('A', 'N', 'I', 'M')) { if (avctx->pix_fmt == AV_PIX_FMT_PAL8 || avctx->pix_fmt == AV_PIX_FMT_GRAY8) { + if (avctx->codec_tag == MKTAG('A', 'N', 'I', 'M')) + memcpy(s->video[0], buf, FFMIN(buf_end - buf, s->video_size)); for (y = 0; y < avctx->height; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memset(row, 0, avctx->width); for (plane = 0; plane < s->bpp && buf < buf_end; plane++) { decodeplane8(row, buf, FFMIN(s->planesize, buf_end - buf), plane); @@ -748,7 +1330,7 @@ static int decode_frame(AVCodecContext *avctx, } } else if (s->ham) { // HAM to AV_PIX_FMT_BGR32 for (y = 0; y < avctx->height; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memset(s->ham_buf, 0, s->planesize * 8); for (plane = 0; plane < s->bpp && buf < buf_end; plane++) { decodeplane8(s->ham_buf, buf, FFMIN(s->planesize, buf_end - buf), plane); @@ -758,7 +1340,7 @@ static int decode_frame(AVCodecContext *avctx, } } else { // AV_PIX_FMT_BGR32 for (y = 0; y < avctx->height; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memset(row, 0, avctx->width << 2); for (plane = 0; plane < s->bpp && buf < buf_end; plane++) { decodeplane32((uint32_t *)row, buf, @@ -770,13 +1352,13 @@ static int decode_frame(AVCodecContext *avctx, } else if (avctx->codec_tag == MKTAG('P', 'B', 'M', ' ')) { // IFF-PBM if (avctx->pix_fmt == AV_PIX_FMT_PAL8 || avctx->pix_fmt == AV_PIX_FMT_GRAY8) { for (y = 0; y < avctx->height && buf_end > buf; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memcpy(row, buf, FFMIN(avctx->width, buf_end - buf)); buf += avctx->width + (avctx->width % 2); // padding if odd } } else if (s->ham) { // IFF-PBM: HAM to AV_PIX_FMT_BGR32 for (y = 0; y < avctx->height && buf_end > buf; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memcpy(s->ham_buf, buf, FFMIN(avctx->width, buf_end - buf)); buf += avctx->width + (avctx->width & 1); // padding if odd decode_ham_plane32((uint32_t *)row, s->ham_buf, s->ham_palbuf, s->planesize); @@ -785,43 +1367,55 @@ static int decode_frame(AVCodecContext *avctx, return unsupported(avctx); } break; - case 1: - if (avctx->codec_tag == MKTAG('I', 'L', 'B', 'M')) { // interleaved + case 0x1: + if (avctx->codec_tag == MKTAG('I', 'L', 'B', 'M') || // interleaved + avctx->codec_tag == MKTAG('A', 'N', 'I', 'M')) { if (avctx->pix_fmt == AV_PIX_FMT_PAL8 || avctx->pix_fmt == AV_PIX_FMT_GRAY8) { + uint8_t *video = s->video[0]; + for (y = 0; y < avctx->height; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memset(row, 0, avctx->width); for (plane = 0; plane < s->bpp; plane++) { - buf += decode_byterun(s->planebuf, s->planesize, buf, buf_end); + buf += decode_byterun(s->planebuf, s->planesize, gb); + if (avctx->codec_tag == MKTAG('A', 'N', 'I', 'M')) { + memcpy(video, s->planebuf, s->planesize); + video += s->planesize; + } decodeplane8(row, s->planebuf, s->planesize, plane); } } } else if (avctx->bits_per_coded_sample <= 8) { //8-bit (+ mask) to AV_PIX_FMT_BGR32 for (y = 0; y < avctx->height; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memset(s->mask_buf, 0, avctx->width * sizeof(uint32_t)); for (plane = 0; plane < s->bpp; plane++) { - buf += decode_byterun(s->planebuf, s->planesize, buf, buf_end); + buf += decode_byterun(s->planebuf, s->planesize, gb); decodeplane32(s->mask_buf, s->planebuf, s->planesize, plane); } lookup_pal_indicies((uint32_t *)row, s->mask_buf, s->mask_palbuf, avctx->width); } } else if (s->ham) { // HAM to AV_PIX_FMT_BGR32 + uint8_t *video = s->video[0]; for (y = 0; y < avctx->height; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memset(s->ham_buf, 0, s->planesize * 8); for (plane = 0; plane < s->bpp; plane++) { - buf += decode_byterun(s->planebuf, s->planesize, buf, buf_end); + buf += decode_byterun(s->planebuf, s->planesize, gb); + if (avctx->codec_tag == MKTAG('A', 'N', 'I', 'M')) { + memcpy(video, s->planebuf, s->planesize); + video += s->planesize; + } decodeplane8(s->ham_buf, s->planebuf, s->planesize, plane); } decode_ham_plane32((uint32_t *)row, s->ham_buf, s->ham_palbuf, s->planesize); } } else { // AV_PIX_FMT_BGR32 for (y = 0; y < avctx->height; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memset(row, 0, avctx->width << 2); for (plane = 0; plane < s->bpp; plane++) { - buf += decode_byterun(s->planebuf, s->planesize, buf, buf_end); + buf += decode_byterun(s->planebuf, s->planesize, gb); decodeplane32((uint32_t *)row, s->planebuf, s->planesize, plane); } } @@ -829,48 +1423,129 @@ static int decode_frame(AVCodecContext *avctx, } else if (avctx->codec_tag == MKTAG('P', 'B', 'M', ' ')) { // IFF-PBM if (avctx->pix_fmt == AV_PIX_FMT_PAL8 || avctx->pix_fmt == AV_PIX_FMT_GRAY8) { for (y = 0; y < avctx->height; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; - buf += decode_byterun(row, avctx->width, buf, buf_end); + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; + buf += decode_byterun(row, avctx->width, gb); } } else if (s->ham) { // IFF-PBM: HAM to AV_PIX_FMT_BGR32 for (y = 0; y < avctx->height; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; - buf += decode_byterun(s->ham_buf, avctx->width, buf, buf_end); + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; + buf += decode_byterun(s->ham_buf, avctx->width, gb); decode_ham_plane32((uint32_t *)row, s->ham_buf, s->ham_palbuf, s->planesize); } } else return unsupported(avctx); } else if (avctx->codec_tag == MKTAG('D', 'E', 'E', 'P')) { // IFF-DEEP if (av_get_bits_per_pixel(desc) == 32) - decode_deep_rle32(s->frame->data[0], buf, buf_size, avctx->width, avctx->height, s->frame->linesize[0]); + decode_deep_rle32(frame->data[0], buf, buf_size, avctx->width, avctx->height, frame->linesize[0]); else return unsupported(avctx); } break; - case 4: - bytestream2_init(&gb, buf, buf_size); + case 0x4: if (avctx->codec_tag == MKTAG('R', 'G', 'B', '8') && avctx->pix_fmt == AV_PIX_FMT_RGB32) - decode_rgb8(&gb, s->frame->data[0], avctx->width, avctx->height, s->frame->linesize[0]); + decode_rgb8(gb, frame->data[0], avctx->width, avctx->height, frame->linesize[0]); else if (avctx->codec_tag == MKTAG('R', 'G', 'B', 'N') && avctx->pix_fmt == AV_PIX_FMT_RGB444) - decode_rgbn(&gb, s->frame->data[0], avctx->width, avctx->height, s->frame->linesize[0]); + decode_rgbn(gb, frame->data[0], avctx->width, avctx->height, frame->linesize[0]); else return unsupported(avctx); break; - case 5: + case 0x5: if (avctx->codec_tag == MKTAG('D', 'E', 'E', 'P')) { if (av_get_bits_per_pixel(desc) == 32) - decode_deep_tvdc32(s->frame->data[0], buf, buf_size, avctx->width, avctx->height, s->frame->linesize[0], s->tvdc); + decode_deep_tvdc32(frame->data[0], buf, buf_size, avctx->width, avctx->height, frame->linesize[0], s->tvdc); else return unsupported(avctx); } else return unsupported(avctx); break; + case 0x500: + case 0x501: + decode_byte_vertical_delta(s->video[0], buf, buf_end, avctx->width, s->bpp, s->video_size); + break; + case 0x700: + case 0x701: + if (s->is_short) + decode_short_vertical_delta(s->video[0], buf, buf_end, avctx->width, s->bpp, s->video_size); + else + decode_long_vertical_delta(s->video[0], buf, buf_end, avctx->width, s->bpp, s->video_size); + break; + case 0x800: + case 0x801: + if (s->is_short) + decode_short_vertical_delta2(s->video[0], buf, buf_end, avctx->width, s->bpp, s->video_size); + else + decode_long_vertical_delta2(s->video[0], buf, buf_end, avctx->width, s->bpp, s->video_size); + break; + case 0x4a00: + case 0x4a01: + decode_delta_j(s->video[0], buf, buf_end, avctx->width, avctx->height, s->bpp, s->video_size); + break; + case 0x6c00: + case 0x6c01: + decode_delta_l(s->video[0], buf, buf_end, avctx->width, s->is_short, s->bpp, s->video_size); + break; default: return unsupported(avctx); } - if ((res = av_frame_ref(data, s->frame)) < 0) - return res; + if (s->compression > 0xff) { + if (avctx->pix_fmt == AV_PIX_FMT_PAL8 || avctx->pix_fmt == AV_PIX_FMT_GRAY8) { + buf = s->video[0]; + for (y = 0; y < avctx->height; y++) { + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; + memset(row, 0, avctx->width); + for (plane = 0; plane < s->bpp; plane++) { + decodeplane8(row, buf, s->planesize, plane); + buf += s->planesize; + } + } + memcpy(frame->data[1], s->pal[0], 256 * 4); + } else if (s->ham) { + int i, count = 1 << s->ham; + + buf = s->video[0]; + memset(s->ham_palbuf, 0, (1 << s->ham) * 2 * sizeof(uint32_t)); + for (i = 0; i < count; i++) { + s->ham_palbuf[i*2+1] = s->pal[0][i]; + } + for (i = 0; i < count; i++) { + uint32_t tmp = i << (8 - s->ham); + tmp |= tmp >> s->ham; + s->ham_palbuf[(i+count)*2] = 0xFF00FFFF; + s->ham_palbuf[(i+count*2)*2] = 0xFFFFFF00; + s->ham_palbuf[(i+count*3)*2] = 0xFFFF00FF; + s->ham_palbuf[(i+count)*2+1] = 0xFF000000 | tmp << 16; + s->ham_palbuf[(i+count*2)*2+1] = 0xFF000000 | tmp; + s->ham_palbuf[(i+count*3)*2+1] = 0xFF000000 | tmp << 8; + } + if (s->masking == MASK_HAS_MASK) { + for (i = 0; i < 8 * (1 << s->ham); i++) + s->ham_palbuf[(1 << s->bpp) + i] = s->ham_palbuf[i] | 0xFF000000; + } + for (y = 0; y < avctx->height; y++) { + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; + memset(s->ham_buf, 0, s->planesize * 8); + for (plane = 0; plane < s->bpp; plane++) { + decodeplane8(s->ham_buf, buf, s->planesize, plane); + buf += s->planesize; + } + decode_ham_plane32((uint32_t *)row, s->ham_buf, s->ham_palbuf, s->planesize); + } + } else { + return unsupported(avctx); + } + + FFSWAP(uint8_t *, s->video[0], s->video[1]); + FFSWAP(uint32_t *, s->pal[0], s->pal[1]); + } + + if (avpkt->flags & AV_PKT_FLAG_KEY) { + frame->key_frame = 1; + frame->pict_type = AV_PICTURE_TYPE_I; + } else { + frame->key_frame = 0; + frame->pict_type = AV_PICTURE_TYPE_P; + } *got_frame = 1; @@ -880,7 +1555,7 @@ static int decode_frame(AVCodecContext *avctx, #if CONFIG_IFF_ILBM_DECODER AVCodec ff_iff_ilbm_decoder = { .name = "iff", - .long_name = NULL_IF_CONFIG_SMALL("IFF"), + .long_name = NULL_IF_CONFIG_SMALL("IFF ACBM/ANIM/DEEP/ILBM/PBM"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_IFF_ILBM, .priv_data_size = sizeof(IffContext), diff --git a/libavformat/iff.c b/libavformat/iff.c index 8b8bf01868..4fb79edfe1 100644 --- a/libavformat/iff.c +++ b/libavformat/iff.c @@ -60,6 +60,8 @@ #define ID_RGBN MKTAG('R','G','B','N') #define ID_DSD MKTAG('D','S','D',' ') #define ID_ANIM MKTAG('A','N','I','M') +#define ID_ANHD MKTAG('A','N','H','D') +#define ID_DLTA MKTAG('D','L','T','A') #define ID_FORM MKTAG('F','O','R','M') #define ID_FRM8 MKTAG('F','R','M','8') @@ -113,6 +115,7 @@ typedef struct IffDemuxContext { unsigned transparency; ///< transparency color index in palette unsigned masking; ///< masking method used uint8_t tvdc[32]; ///< TVDC lookup table + int64_t pts; } IffDemuxContext; /* Metadata string read */ @@ -147,7 +150,6 @@ static int iff_probe(AVProbeData *p) AV_RL32(d+8) == ID_DEEP || AV_RL32(d+8) == ID_ILBM || AV_RL32(d+8) == ID_RGB8 || - AV_RL32(d+8) == ID_RGB8 || AV_RL32(d+8) == ID_ANIM || AV_RL32(d+8) == ID_RGBN)) || (AV_RL32(d) == ID_FRM8 && AV_RL32(d+12) == ID_DSD)) @@ -367,8 +369,7 @@ static int iff_read_header(AVFormatContext *s) // codec_tag used by ByteRun1 decoder to distinguish progressive (PBM) and interlaced (ILBM) content st->codecpar->codec_tag = avio_rl32(pb); if (st->codecpar->codec_tag == ID_ANIM) { - avio_skip(pb, 8); - st->codecpar->codec_tag = avio_rl32(pb); + avio_skip(pb, 12); } iff->bitmap_compression = -1; iff->svx8_compression = -1; @@ -484,6 +485,9 @@ static int iff_read_header(AVFormatContext *s) } break; + case ID_ANHD: + break; + case ID_DPEL: if (data_size < 4 || (data_size & 3)) return AVERROR_INVALIDDATA; @@ -626,7 +630,10 @@ static int iff_read_header(AVFormatContext *s) avio_skip(pb, data_size - (avio_tell(pb) - orig_pos) + (data_size & 1)); } - avio_seek(pb, iff->body_pos, SEEK_SET); + if (st->codecpar->codec_tag == ID_ANIM) + avio_seek(pb, 12, SEEK_SET); + else + avio_seek(pb, iff->body_pos, SEEK_SET); switch(st->codecpar->codec_type) { case AVMEDIA_TYPE_AUDIO: @@ -672,6 +679,8 @@ static int iff_read_header(AVFormatContext *s) case AVMEDIA_TYPE_VIDEO: iff->bpp = st->codecpar->bits_per_coded_sample; + if (st->codecpar->codec_tag == ID_ANIM) + avpriv_set_pts_info(st, 32, 1, 60); if ((screenmode & 0x800 /* Hold And Modify */) && iff->bpp <= 8) { iff->ham = iff->bpp > 6 ? 6 : 4; st->codecpar->bits_per_coded_sample = 24; @@ -705,6 +714,28 @@ static int iff_read_header(AVFormatContext *s) return 0; } +static unsigned get_anim_duration(uint8_t *buf, int size) +{ + GetByteContext gb; + + bytestream2_init(&gb, buf, size); + bytestream2_skip(&gb, 4); + while (bytestream2_get_bytes_left(&gb) > 8) { + unsigned chunk = bytestream2_get_le32(&gb); + unsigned size = bytestream2_get_be32(&gb); + + if (chunk == ID_ANHD) { + if (size < 40) + break; + bytestream2_skip(&gb, 14); + return bytestream2_get_be32(&gb); + } else { + bytestream2_skip(&gb, size + size & 1); + } + } + return 10; +} + static int iff_read_packet(AVFormatContext *s, AVPacket *pkt) { @@ -714,8 +745,12 @@ static int iff_read_packet(AVFormatContext *s, int ret; int64_t pos = avio_tell(pb); - if (pos >= iff->body_end) + if (st->codecpar->codec_tag == ID_ANIM) { + if (avio_feof(pb)) + return AVERROR_EOF; + } else if (pos >= iff->body_end) { return AVERROR_EOF; + } if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { if (st->codecpar->codec_tag == ID_DSD || st->codecpar->codec_tag == ID_MAUD) { @@ -725,28 +760,39 @@ static int iff_read_packet(AVFormatContext *s, return AVERROR_INVALIDDATA; ret = av_get_packet(pb, pkt, iff->body_size); } - } else if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { - uint8_t *buf; + } else if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && + st->codecpar->codec_tag == ID_ANIM) { + uint64_t data_size, orig_pos; + uint32_t chunk_id = 0; - if (iff->body_size > INT_MAX - 2) - return AVERROR_INVALIDDATA; - if (av_new_packet(pkt, iff->body_size + 2) < 0) { - return AVERROR(ENOMEM); - } + while (!avio_feof(pb)) { + if (avio_feof(pb)) + return AVERROR_EOF; + + chunk_id = avio_rl32(pb); + data_size = avio_rb32(pb); + orig_pos = avio_tell(pb); - buf = pkt->data; - bytestream_put_be16(&buf, 2); - ret = avio_read(pb, buf, iff->body_size); - if (ret<0) { - av_packet_unref(pkt); - } else if (ret < iff->body_size) - av_shrink_packet(pkt, ret + 2); + if (chunk_id == ID_FORM) + break; + else + avio_skip(pb, data_size); + } + ret = av_get_packet(pb, pkt, data_size); + pkt->pos = orig_pos; + pkt->duration = get_anim_duration(pkt->data, pkt->size); + if (pos == 12) + pkt->flags |= AV_PKT_FLAG_KEY; + } else if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && + st->codecpar->codec_tag != ID_ANIM) { + ret = av_get_packet(pb, pkt, iff->body_size); + pkt->pos = pos; + if (pos == iff->body_pos) + pkt->flags |= AV_PKT_FLAG_KEY; } else { av_assert0(0); } - if (pos == iff->body_pos) - pkt->flags |= AV_PKT_FLAG_KEY; if (ret < 0) return ret; pkt->stream_index = 0; |