aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul B Mahol <onemda@gmail.com>2016-05-10 23:48:50 +0200
committerPaul B Mahol <onemda@gmail.com>2016-05-13 00:24:48 +0200
commitcb928fc448f9566e6f6c28d53fa4c2388e732a2b (patch)
tree6d737ef94f98f055cdc4aa6b2cc3af3618bc609a
parent97946b20b6d8c8746ca41490534d7ecceaab799b (diff)
downloadffmpeg-cb928fc448f9566e6f6c28d53fa4c2388e732a2b.tar.gz
lavc: add IFF ANIM decoder
Signed-off-by: Paul B Mahol <onemda@gmail.com>
-rw-r--r--Changelog1
-rw-r--r--libavcodec/codec_desc.c2
-rw-r--r--libavcodec/iff.c825
-rw-r--r--libavformat/iff.c88
4 files changed, 819 insertions, 97 deletions
diff --git a/Changelog b/Changelog
index 46f0ecbea5..3f343cec98 100644
--- a/Changelog
+++ b/Changelog
@@ -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;