Commit cb928fc4 authored by Paul B Mahol's avatar Paul B Mahol

lavc: add IFF ANIM decoder

Signed-off-by: 's avatarPaul B Mahol <onemda@gmail.com>
parent 97946b20
...@@ -33,6 +33,7 @@ version <next>: ...@@ -33,6 +33,7 @@ version <next>:
- VAAPI-accelerated H.264/HEVC/MJPEG encoding - VAAPI-accelerated H.264/HEVC/MJPEG encoding
- DTS Express (LBR) decoder - DTS Express (LBR) decoder
- Generic OpenMAX IL encoder with support for Raspberry Pi - Generic OpenMAX IL encoder with support for Raspberry Pi
- IFF ANIM demuxer & decoder
version 3.0: version 3.0:
- Common Encryption (CENC) MP4 encoding and decoding support - Common Encryption (CENC) MP4 encoding and decoding support
......
...@@ -887,7 +887,7 @@ static const AVCodecDescriptor codec_descriptors[] = { ...@@ -887,7 +887,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.id = AV_CODEC_ID_IFF_ILBM, .id = AV_CODEC_ID_IFF_ILBM,
.type = AVMEDIA_TYPE_VIDEO, .type = AVMEDIA_TYPE_VIDEO,
.name = "iff_ilbm", .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, .props = AV_CODEC_PROP_LOSSY,
}, },
{ {
......
/* /*
* 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 Peter Ross <pross@xvid.org>
* Copyright (c) 2010 Sebastian Vater <cdgs.basty@googlemail.com> * Copyright (c) 2010 Sebastian Vater <cdgs.basty@googlemail.com>
* Copyright (c) 2016 Paul B Mahol
* *
* This file is part of FFmpeg. * This file is part of FFmpeg.
* *
...@@ -22,7 +23,7 @@ ...@@ -22,7 +23,7 @@
/** /**
* @file * @file
* IFF ACBM/DEEP/ILBM/PBM bitmap decoder * IFF ACBM/ANIM/DEEP/ILBM/PBM bitmap decoder
*/ */
#include <stdint.h> #include <stdint.h>
...@@ -30,8 +31,8 @@ ...@@ -30,8 +31,8 @@
#include "libavutil/imgutils.h" #include "libavutil/imgutils.h"
#include "bytestream.h" #include "bytestream.h"
#include "avcodec.h" #include "avcodec.h"
#include "get_bits.h"
#include "internal.h" #include "internal.h"
#include "mathops.h"
// TODO: masking bits // TODO: masking bits
typedef enum { typedef enum {
...@@ -50,6 +51,7 @@ typedef struct IffContext { ...@@ -50,6 +51,7 @@ typedef struct IffContext {
uint32_t *mask_buf; ///< temporary buffer for palette indices uint32_t *mask_buf; ///< temporary buffer for palette indices
uint32_t *mask_palbuf; ///< masking palette table uint32_t *mask_palbuf; ///< masking palette table
unsigned compression; ///< delta compression method used 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 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 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 unsigned flags; ///< 1 for EHB, 0 is no extra half darkening
...@@ -57,6 +59,11 @@ typedef struct IffContext { ...@@ -57,6 +59,11 @@ typedef struct IffContext {
unsigned masking; ///< TODO: masking method used unsigned masking; ///< TODO: masking method used
int init; // 1 if buffer and palette data already initialized, 0 otherwise int init; // 1 if buffer and palette data already initialized, 0 otherwise
int16_t tvdc[16]; ///< TVDC lookup table int16_t tvdc[16]; ///< TVDC lookup table
GetByteContext gb;
uint8_t *video[2];
unsigned video_size;
uint32_t *pal[2];
int first;
} IffContext; } IffContext;
#define LUT8_PART(plane, v) \ #define LUT8_PART(plane, v) \
...@@ -189,10 +196,11 @@ static int cmap_read_palette(AVCodecContext *avctx, uint32_t *pal) ...@@ -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 * @return >= 0 in case of success, a negative error code otherwise
*/ */
static int extract_header(AVCodecContext *const avctx, static int extract_header(AVCodecContext *const avctx,
const AVPacket *const avpkt) { const AVPacket *const avpkt)
const uint8_t *buf; {
unsigned buf_size;
IffContext *s = avctx->priv_data; IffContext *s = avctx->priv_data;
const uint8_t *buf;
unsigned buf_size = 0;
int i, palette_size; int i, palette_size;
if (avctx->extradata_size < 2) { if (avctx->extradata_size < 2) {
...@@ -201,20 +209,51 @@ static int extract_header(AVCodecContext *const avctx, ...@@ -201,20 +209,51 @@ static int extract_header(AVCodecContext *const avctx,
} }
palette_size = avctx->extradata_size - AV_RB16(avctx->extradata); palette_size = avctx->extradata_size - AV_RB16(avctx->extradata);
if (avpkt) { if (avpkt && avctx->codec_tag == MKTAG('A', 'N', 'I', 'M')) {
int image_size; uint32_t chunk_id;
if (avpkt->size < 2) uint64_t data_size;
return AVERROR_INVALIDDATA; GetByteContext *gb = &s->gb;
image_size = avpkt->size - AV_RB16(avpkt->data);
buf = avpkt->data; bytestream2_skip(gb, 4);
buf_size = bytestream_get_be16(&buf); while (bytestream2_get_bytes_left(gb) >= 1) {
if (buf_size <= 1 || image_size <= 1) { chunk_id = bytestream2_get_le32(gb);
av_log(avctx, AV_LOG_ERROR, data_size = bytestream2_get_be32(gb);
"Invalid image size received: %u -> image data offset: %d\n",
buf_size, image_size); if (chunk_id == MKTAG('B', 'M', 'H', 'D')) {
return AVERROR_INVALIDDATA; 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 = avctx->extradata;
buf_size = bytestream_get_be16(&buf); buf_size = bytestream_get_be16(&buf);
if (buf_size <= 1 || palette_size < 0) { if (buf_size <= 1 || palette_size < 0) {
...@@ -323,10 +362,13 @@ static int extract_header(AVCodecContext *const avctx, ...@@ -323,10 +362,13 @@ static int extract_header(AVCodecContext *const avctx,
static av_cold int decode_end(AVCodecContext *avctx) static av_cold int decode_end(AVCodecContext *avctx)
{ {
IffContext *s = avctx->priv_data; IffContext *s = avctx->priv_data;
av_frame_free(&s->frame);
av_freep(&s->planebuf); av_freep(&s->planebuf);
av_freep(&s->ham_buf); av_freep(&s->ham_buf);
av_freep(&s->ham_palbuf); 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; return 0;
} }
...@@ -371,10 +413,16 @@ static av_cold int decode_init(AVCodecContext *avctx) ...@@ -371,10 +413,16 @@ static av_cold int decode_init(AVCodecContext *avctx)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
s->bpp = avctx->bits_per_coded_sample; s->bpp = avctx->bits_per_coded_sample;
s->frame = av_frame_alloc();
if (!s->frame) { if (avctx->codec_tag == MKTAG('A', 'N', 'I', 'M')) {
decode_end(avctx); s->video_size = FFALIGN(avctx->width, 2) * avctx->height * s->bpp;
return AVERROR(ENOMEM); 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) if ((err = extract_header(avctx, NULL)) < 0)
...@@ -480,20 +528,18 @@ static void lookup_pal_indicies(uint32_t *dst, const uint32_t *buf, ...@@ -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 * @return number of consumed bytes in byterun1 compressed bitstream
*/ */
static int decode_byterun(uint8_t *dst, int dst_size, 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; 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; unsigned length;
const int8_t value = *buf++; const int8_t value = bytestream2_get_byte(gb);
if (value >= 0) { if (value >= 0) {
length = FFMIN3(value + 1, dst_size - x, buf_end - buf); length = FFMIN3(value + 1, dst_size - x, bytestream2_get_bytes_left(gb));
memcpy(dst + x, buf, length); bytestream2_get_buffer(gb, dst + x, length);
buf += length;
} else if (value > -128) { } else if (value > -128) {
length = FFMIN(-value + 1, dst_size - x); length = FFMIN(-value + 1, dst_size - x);
memset(dst + x, *buf++, length); memset(dst + x, bytestream2_get_byte(gb), length);
} else { // noop } else { // noop
continue; continue;
} }
...@@ -503,7 +549,7 @@ static int decode_byterun(uint8_t *dst, int dst_size, ...@@ -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"); av_log(NULL, AV_LOG_WARNING, "decode_byterun ended before plane size\n");
memset(dst+x, 0, dst_size - x); memset(dst+x, 0, dst_size - x);
} }
return buf - buf_start; return bytestream2_tell(gb);
} }
#define DECODE_RGBX_COMMON(type) \ #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 ...@@ -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) static int unsupported(AVCodecContext *avctx)
{ {
IffContext *s = avctx->priv_data; 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; return AVERROR_INVALIDDATA;
} }
...@@ -672,23 +1233,30 @@ static int decode_frame(AVCodecContext *avctx, ...@@ -672,23 +1233,30 @@ static int decode_frame(AVCodecContext *avctx,
AVPacket *avpkt) AVPacket *avpkt)
{ {
IffContext *s = avctx->priv_data; IffContext *s = avctx->priv_data;
const uint8_t *buf = avpkt->size >= 2 ? avpkt->data + AV_RB16(avpkt->data) : NULL; AVFrame *frame = data;
const int buf_size = avpkt->size >= 2 ? avpkt->size - AV_RB16(avpkt->data) : 0; const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
const uint8_t *buf_end = buf + buf_size; const uint8_t *buf_end = buf + buf_size;
int y, plane, res; int y, plane, res;
GetByteContext gb; GetByteContext *gb = &s->gb;
const AVPixFmtDescriptor *desc; const AVPixFmtDescriptor *desc;
bytestream2_init(gb, avpkt->data, avpkt->size);
if ((res = extract_header(avctx, avpkt)) < 0) if ((res = extract_header(avctx, avpkt)) < 0)
return res; return res;
if ((res = ff_reget_buffer(avctx, s->frame)) < 0)
if ((res = ff_get_buffer(avctx, frame, 0)) < 0)
return res; return res;
s->frame = frame;
buf += bytestream2_tell(gb);
buf_size -= bytestream2_tell(gb);
desc = av_pix_fmt_desc_get(avctx->pix_fmt); desc = av_pix_fmt_desc_get(avctx->pix_fmt);
if (!s->init && avctx->bits_per_coded_sample <= 8 && if (!s->init && avctx->bits_per_coded_sample <= 8 &&
avctx->pix_fmt == AV_PIX_FMT_PAL8) { 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; return res;
} else if (!s->init && avctx->bits_per_coded_sample <= 8 && } else if (!s->init && avctx->bits_per_coded_sample <= 8 &&
avctx->pix_fmt == AV_PIX_FMT_RGB32) { avctx->pix_fmt == AV_PIX_FMT_RGB32) {
...@@ -697,22 +1265,33 @@ static int decode_frame(AVCodecContext *avctx, ...@@ -697,22 +1265,33 @@ static int decode_frame(AVCodecContext *avctx,
} }
s->init = 1; 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) { switch (s->compression) {
case 0: case 0x0:
if (avctx->codec_tag == MKTAG('A', 'C', 'B', 'M')) { if (avctx->codec_tag == MKTAG('A', 'C', 'B', 'M')) {
if (avctx->pix_fmt == AV_PIX_FMT_PAL8 || avctx->pix_fmt == AV_PIX_FMT_GRAY8) { 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 (plane = 0; plane < s->bpp; plane++) {
for (y = 0; y < avctx->height && buf < buf_end; y++) { 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); decodeplane8(row, buf, FFMIN(s->planesize, buf_end - buf), plane);
buf += s->planesize; buf += s->planesize;
} }
} }
} else if (s->ham) { // HAM to AV_PIX_FMT_BGR32 } 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++) { 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); memset(s->ham_buf, 0, s->planesize * 8);
for (plane = 0; plane < s->bpp; plane++) { for (plane = 0; plane < s->bpp; plane++) {
const uint8_t * start = buf + (plane * avctx->height + y) * s->planesize; const uint8_t * start = buf + (plane * avctx->height + y) * s->planesize;
...@@ -728,7 +1307,7 @@ static int decode_frame(AVCodecContext *avctx, ...@@ -728,7 +1307,7 @@ static int decode_frame(AVCodecContext *avctx,
int raw_width = avctx->width * (av_get_bits_per_pixel(desc) >> 3); int raw_width = avctx->width * (av_get_bits_per_pixel(desc) >> 3);
int x; int x;
for (y = 0; y < avctx->height && buf < buf_end; y++) { 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)); memcpy(row, buf, FFMIN(raw_width, buf_end - buf));
buf += raw_width; buf += raw_width;
if (avctx->pix_fmt == AV_PIX_FMT_BGR32) { if (avctx->pix_fmt == AV_PIX_FMT_BGR32) {
...@@ -736,10 +1315,13 @@ static int decode_frame(AVCodecContext *avctx, ...@@ -736,10 +1315,13 @@ static int decode_frame(AVCodecContext *avctx,
row[4 * x + 3] = row[4 * x + 3] & 0xF0 | (row[4 * x + 3] >> 4); 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->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++) { 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); memset(row, 0, avctx->width);
for (plane = 0; plane < s->bpp && buf < buf_end; plane++) { for (plane = 0; plane < s->bpp && buf < buf_end; plane++) {
decodeplane8(row, buf, FFMIN(s->planesize, buf_end - buf), plane); decodeplane8(row, buf, FFMIN(s->planesize, buf_end - buf), plane);
...@@ -748,7 +1330,7 @@ static int decode_frame(AVCodecContext *avctx, ...@@ -748,7 +1330,7 @@ static int decode_frame(AVCodecContext *avctx,
} }
} else if (s->ham) { // HAM to AV_PIX_FMT_BGR32 } else if (s->ham) { // HAM to AV_PIX_FMT_BGR32
for (y = 0; y < avctx->height; y++) { 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); memset(s->ham_buf, 0, s->planesize * 8);
for (plane = 0; plane < s->bpp && buf < buf_end; plane++) { for (plane = 0; plane < s->bpp && buf < buf_end; plane++) {
decodeplane8(s->ham_buf, buf, FFMIN(s->planesize, buf_end - buf), plane); decodeplane8(s->ham_buf, buf, FFMIN(s->planesize, buf_end - buf), plane);
...@@ -758,7 +1340,7 @@ static int decode_frame(AVCodecContext *avctx, ...@@ -758,7 +1340,7 @@ static int decode_frame(AVCodecContext *avctx,
} }
} else { // AV_PIX_FMT_BGR32 } else { // AV_PIX_FMT_BGR32
for (y = 0; y < avctx->height; y++) { 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); memset(row, 0, avctx->width << 2);
for (plane = 0; plane < s->bpp && buf < buf_end; plane++) { for (plane = 0; plane < s->bpp && buf < buf_end; plane++) {
decodeplane32((uint32_t *)row, buf, decodeplane32((uint32_t *)row, buf,
...@@ -770,13 +1352,13 @@ static int decode_frame(AVCodecContext *avctx, ...@@ -770,13 +1352,13 @@ static int decode_frame(AVCodecContext *avctx,
} else if (avctx->codec_tag == MKTAG('P', 'B', 'M', ' ')) { // IFF-PBM } 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) { 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++) { 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)); memcpy(row, buf, FFMIN(avctx->width, buf_end - buf));
buf += avctx->width + (avctx->width % 2); // padding if odd buf += avctx->width + (avctx->width % 2); // padding if odd
} }
} else if (s->ham) { // IFF-PBM: HAM to AV_PIX_FMT_BGR32 } else if (s->ham) { // IFF-PBM: HAM to AV_PIX_FMT_BGR32
for (y = 0; y < avctx->height && buf_end > buf; y++) { 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)); memcpy(s->ham_buf, buf, FFMIN(avctx->width, buf_end - buf));
buf += avctx->width + (avctx->width & 1); // padding if odd buf += avctx->width + (avctx->width & 1); // padding if odd
decode_ham_plane32((uint32_t *)row, s->ham_buf, s->ham_palbuf, s->planesize); decode_ham_plane32((uint32_t *)row, s->ham_buf, s->ham_palbuf, s->planesize);
...@@ -785,43 +1367,55 @@ static int decode_frame(AVCodecContext *avctx, ...@@ -785,43 +1367,55 @@ static int decode_frame(AVCodecContext *avctx,
return unsupported(avctx); return unsupported(avctx);
} }
break; break;
case 1: case 0x1:
if (avctx->codec_tag == MKTAG('I', 'L', 'B', 'M')) { // interleaved 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->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++) { 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); memset(row, 0, avctx->width);
for (plane = 0; plane < s->bpp; plane++) { 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); decodeplane8(row, s->planebuf, s->planesize, plane);
} }
} }
} else if (avctx->bits_per_coded_sample <= 8) { //8-bit (+ mask) to AV_PIX_FMT_BGR32 } else if (avctx->bits_per_coded_sample <= 8) { //8-bit (+ mask) to AV_PIX_FMT_BGR32
for (y = 0; y < avctx->height; y++) { 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)); memset(s->mask_buf, 0, avctx->width * sizeof(uint32_t));
for (plane = 0; plane < s->bpp; plane++) { 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); decodeplane32(s->mask_buf, s->planebuf, s->planesize, plane);
} }
lookup_pal_indicies((uint32_t *)row, s->mask_buf, s->mask_palbuf, avctx->width); lookup_pal_indicies((uint32_t *)row, s->mask_buf, s->mask_palbuf, avctx->width);
} }
} else if (s->ham) { // HAM to AV_PIX_FMT_BGR32 } else if (s->ham) { // HAM to AV_PIX_FMT_BGR32
uint8_t *video = s->video[0];
for (y = 0; y < avctx->height; y++) { 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); memset(s->ham_buf, 0, s->planesize * 8);
for (plane = 0; plane < s->bpp; plane++) { 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); decodeplane8(s->ham_buf, s->planebuf, s->planesize, plane);
} }
decode_ham_plane32((uint32_t *)row, s->ham_buf, s->ham_palbuf, s->planesize); decode_ham_plane32((uint32_t *)row, s->ham_buf, s->ham_palbuf, s->planesize);
} }
} else { // AV_PIX_FMT_BGR32 } else { // AV_PIX_FMT_BGR32
for (y = 0; y < avctx->height; y++) { 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); memset(row, 0, avctx->width << 2);
for (plane = 0; plane < s->bpp; plane++) { 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); decodeplane32((uint32_t *)row, s->planebuf, s->planesize, plane);
} }
} }
...@@ -829,48 +1423,129 @@ static int decode_frame(AVCodecContext *avctx, ...@@ -829,48 +1423,129 @@ static int decode_frame(AVCodecContext *avctx,
} else if (avctx->codec_tag == MKTAG('P', 'B', 'M', ' ')) { // IFF-PBM } 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) { if (avctx->pix_fmt == AV_PIX_FMT_PAL8 || avctx->pix_fmt == AV_PIX_FMT_GRAY8) {
for (y = 0; y < avctx->height; y++) { 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]];
buf += decode_byterun(row, avctx->width, buf, buf_end); buf += decode_byterun(row, avctx->width, gb);
} }
} else if (s->ham) { // IFF-PBM: HAM to AV_PIX_FMT_BGR32 } else if (s->ham) { // IFF-PBM: HAM to AV_PIX_FMT_BGR32
for (y = 0; y < avctx->height; y++) { 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]];
buf += decode_byterun(s->ham_buf, avctx->width, buf, buf_end); buf += decode_byterun(s->ham_buf, avctx->width, gb);
decode_ham_plane32((uint32_t *)row, s->ham_buf, s->ham_palbuf, s->planesize); decode_ham_plane32((uint32_t *)row, s->ham_buf, s->ham_palbuf, s->planesize);
} }
} else } else
return unsupported(avctx); return unsupported(avctx);
} else if (avctx->codec_tag == MKTAG('D', 'E', 'E', 'P')) { // IFF-DEEP } else if (avctx->codec_tag == MKTAG('D', 'E', 'E', 'P')) { // IFF-DEEP
if (av_get_bits_per_pixel(desc) == 32) 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 else
return unsupported(avctx); return unsupported(avctx);
} }
break; break;
case 4: case 0x4:
bytestream2_init(&gb, buf, buf_size);
if (avctx->codec_tag == MKTAG('R', 'G', 'B', '8') && avctx->pix_fmt == AV_PIX_FMT_RGB32) 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) 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 else
return unsupported(avctx); return unsupported(avctx);
break; break;
case 5: case 0x5:
if (avctx->codec_tag == MKTAG('D', 'E', 'E', 'P')) { if (avctx->codec_tag == MKTAG('D', 'E', 'E', 'P')) {
if (av_get_bits_per_pixel(desc) == 32) 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 else
return unsupported(avctx); return unsupported(avctx);
} else } else
return unsupported(avctx); return unsupported(avctx);
break; 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: default:
return unsupported(avctx); return unsupported(avctx);
} }
if ((res = av_frame_ref(data, s->frame)) < 0) if (s->compression > 0xff) {
return res; 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; *got_frame = 1;
...@@ -880,7 +1555,7 @@ static int decode_frame(AVCodecContext *avctx, ...@@ -880,7 +1555,7 @@ static int decode_frame(AVCodecContext *avctx,
#if CONFIG_IFF_ILBM_DECODER #if CONFIG_IFF_ILBM_DECODER
AVCodec ff_iff_ilbm_decoder = { AVCodec ff_iff_ilbm_decoder = {
.name = "iff", .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, .type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_IFF_ILBM, .id = AV_CODEC_ID_IFF_ILBM,
.priv_data_size = sizeof(IffContext), .priv_data_size = sizeof(IffContext),
......
...@@ -60,6 +60,8 @@ ...@@ -60,6 +60,8 @@
#define ID_RGBN MKTAG('R','G','B','N') #define ID_RGBN MKTAG('R','G','B','N')
#define ID_DSD MKTAG('D','S','D',' ') #define ID_DSD MKTAG('D','S','D',' ')
#define ID_ANIM MKTAG('A','N','I','M') #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_FORM MKTAG('F','O','R','M')
#define ID_FRM8 MKTAG('F','R','M','8') #define ID_FRM8 MKTAG('F','R','M','8')
...@@ -113,6 +115,7 @@ typedef struct IffDemuxContext { ...@@ -113,6 +115,7 @@ typedef struct IffDemuxContext {
unsigned transparency; ///< transparency color index in palette unsigned transparency; ///< transparency color index in palette
unsigned masking; ///< masking method used unsigned masking; ///< masking method used
uint8_t tvdc[32]; ///< TVDC lookup table uint8_t tvdc[32]; ///< TVDC lookup table
int64_t pts;
} IffDemuxContext; } IffDemuxContext;
/* Metadata string read */ /* Metadata string read */
...@@ -147,7 +150,6 @@ static int iff_probe(AVProbeData *p) ...@@ -147,7 +150,6 @@ static int iff_probe(AVProbeData *p)
AV_RL32(d+8) == ID_DEEP || AV_RL32(d+8) == ID_DEEP ||
AV_RL32(d+8) == ID_ILBM || AV_RL32(d+8) == ID_ILBM ||
AV_RL32(d+8) == ID_RGB8 || AV_RL32(d+8) == ID_RGB8 ||
AV_RL32(d+8) == ID_RGB8 ||
AV_RL32(d+8) == ID_ANIM || AV_RL32(d+8) == ID_ANIM ||
AV_RL32(d+8) == ID_RGBN)) || AV_RL32(d+8) == ID_RGBN)) ||
(AV_RL32(d) == ID_FRM8 && AV_RL32(d+12) == ID_DSD)) (AV_RL32(d) == ID_FRM8 && AV_RL32(d+12) == ID_DSD))
...@@ -367,8 +369,7 @@ static int iff_read_header(AVFormatContext *s) ...@@ -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 // codec_tag used by ByteRun1 decoder to distinguish progressive (PBM) and interlaced (ILBM) content
st->codecpar->codec_tag = avio_rl32(pb); st->codecpar->codec_tag = avio_rl32(pb);
if (st->codecpar->codec_tag == ID_ANIM) { if (st->codecpar->codec_tag == ID_ANIM) {
avio_skip(pb, 8); avio_skip(pb, 12);
st->codecpar->codec_tag = avio_rl32(pb);
} }
iff->bitmap_compression = -1; iff->bitmap_compression = -1;
iff->svx8_compression = -1; iff->svx8_compression = -1;
...@@ -484,6 +485,9 @@ static int iff_read_header(AVFormatContext *s) ...@@ -484,6 +485,9 @@ static int iff_read_header(AVFormatContext *s)
} }
break; break;
case ID_ANHD:
break;
case ID_DPEL: case ID_DPEL:
if (data_size < 4 || (data_size & 3)) if (data_size < 4 || (data_size & 3))
return AVERROR_INVALIDDATA; return AVERROR_INVALIDDATA;
...@@ -626,7 +630,10 @@ static int iff_read_header(AVFormatContext *s) ...@@ -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_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) { switch(st->codecpar->codec_type) {
case AVMEDIA_TYPE_AUDIO: case AVMEDIA_TYPE_AUDIO:
...@@ -672,6 +679,8 @@ static int iff_read_header(AVFormatContext *s) ...@@ -672,6 +679,8 @@ static int iff_read_header(AVFormatContext *s)
case AVMEDIA_TYPE_VIDEO: case AVMEDIA_TYPE_VIDEO:
iff->bpp = st->codecpar->bits_per_coded_sample; 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) { if ((screenmode & 0x800 /* Hold And Modify */) && iff->bpp <= 8) {
iff->ham = iff->bpp > 6 ? 6 : 4; iff->ham = iff->bpp > 6 ? 6 : 4;
st->codecpar->bits_per_coded_sample = 24; st->codecpar->bits_per_coded_sample = 24;
...@@ -705,6 +714,28 @@ static int iff_read_header(AVFormatContext *s) ...@@ -705,6 +714,28 @@ static int iff_read_header(AVFormatContext *s)
return 0; 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, static int iff_read_packet(AVFormatContext *s,
AVPacket *pkt) AVPacket *pkt)
{ {
...@@ -714,8 +745,12 @@ static int iff_read_packet(AVFormatContext *s, ...@@ -714,8 +745,12 @@ static int iff_read_packet(AVFormatContext *s,
int ret; int ret;
int64_t pos = avio_tell(pb); 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; return AVERROR_EOF;
}
if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
if (st->codecpar->codec_tag == ID_DSD || st->codecpar->codec_tag == ID_MAUD) { if (st->codecpar->codec_tag == ID_DSD || st->codecpar->codec_tag == ID_MAUD) {
...@@ -725,28 +760,39 @@ static int iff_read_packet(AVFormatContext *s, ...@@ -725,28 +760,39 @@ static int iff_read_packet(AVFormatContext *s,
return AVERROR_INVALIDDATA; return AVERROR_INVALIDDATA;
ret = av_get_packet(pb, pkt, iff->body_size); ret = av_get_packet(pb, pkt, iff->body_size);
} }
} else if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { } else if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
uint8_t *buf; st->codecpar->codec_tag == ID_ANIM) {
uint64_t data_size, orig_pos;
uint32_t chunk_id = 0;
if (iff->body_size > INT_MAX - 2) while (!avio_feof(pb)) {
return AVERROR_INVALIDDATA; if (avio_feof(pb))
if (av_new_packet(pkt, iff->body_size + 2) < 0) { return AVERROR_EOF;
return AVERROR(ENOMEM);
} chunk_id = avio_rl32(pb);
data_size = avio_rb32(pb);
orig_pos = avio_tell(pb);
buf = pkt->data; if (chunk_id == ID_FORM)
bytestream_put_be16(&buf, 2); break;
ret = avio_read(pb, buf, iff->body_size); else
if (ret<0) { avio_skip(pb, data_size);
av_packet_unref(pkt); }
} else if (ret < iff->body_size) ret = av_get_packet(pb, pkt, data_size);
av_shrink_packet(pkt, ret + 2); 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 { } else {
av_assert0(0); av_assert0(0);
} }
if (pos == iff->body_pos)
pkt->flags |= AV_PKT_FLAG_KEY;
if (ret < 0) if (ret < 0)
return ret; return ret;
pkt->stream_index = 0; pkt->stream_index = 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment