summaryrefslogtreecommitdiff
path: root/libavcodec/iff.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavcodec/iff.c')
-rw-r--r--libavcodec/iff.c1703
1 files changed, 1594 insertions, 109 deletions
diff --git a/libavcodec/iff.c b/libavcodec/iff.c
index a186e3185c..075ada6ddd 100644
--- a/libavcodec/iff.c
+++ b/libavcodec/iff.c
@@ -1,28 +1,29 @@
/*
- * IFF PBM/ILBM bitmap decoder
+ * IFF ACBM/ANIM/DEEP/ILBM/PBM/RGB8/RGBN 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 Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
- * IFF PBM/ILBM bitmap decoder
+ * IFF ACBM/ANIM/DEEP/ILBM/PBM/RGB8/RGBN bitmap decoder
*/
#include <stdint.h>
@@ -32,12 +33,39 @@
#include "bytestream.h"
#include "avcodec.h"
#include "internal.h"
+#include "mathops.h"
+
+// TODO: masking bits
+typedef enum {
+ MASK_NONE,
+ MASK_HAS_MASK,
+ MASK_HAS_TRANSPARENT_COLOR,
+ MASK_LASSO
+} mask_type;
typedef struct IffContext {
AVFrame *frame;
int planesize;
uint8_t * planebuf;
+ uint8_t * ham_buf; ///< temporary buffer for planar to chunky conversation
+ uint32_t *ham_palbuf; ///< HAM decode table
+ 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 is_interlaced;///< video is interlaced
+ unsigned is_brush; ///< video is in ANBR format
+ 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
+ unsigned transparency; ///< TODO: transparency color index in palette
+ 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;
} IffContext;
#define LUT8_PART(plane, v) \
@@ -124,33 +152,228 @@ static av_always_inline uint32_t gray2rgb(const uint32_t x) {
*/
static int cmap_read_palette(AVCodecContext *avctx, uint32_t *pal)
{
+ IffContext *s = avctx->priv_data;
int count, i;
+ const uint8_t *const palette = avctx->extradata + AV_RB16(avctx->extradata);
+ int palette_size = avctx->extradata_size - AV_RB16(avctx->extradata);
if (avctx->bits_per_coded_sample > 8) {
- av_log(avctx, AV_LOG_ERROR, "bit_per_coded_sample > 8 not supported\n");
+ av_log(avctx, AV_LOG_ERROR, "bits_per_coded_sample > 8 not supported\n");
return AVERROR_INVALIDDATA;
}
count = 1 << avctx->bits_per_coded_sample;
// If extradata is smaller than actually needed, fill the remaining with black.
- count = FFMIN(avctx->extradata_size / 3, count);
+ count = FFMIN(palette_size / 3, count);
if (count) {
for (i = 0; i < count; i++)
- pal[i] = 0xFF000000 | AV_RB24(avctx->extradata + i * 3);
+ pal[i] = 0xFF000000 | AV_RB24(palette + i*3);
+ if (s->flags && count >= 32) { // EHB
+ for (i = 0; i < 32; i++)
+ pal[i + 32] = 0xFF000000 | (AV_RB24(palette + i*3) & 0xFEFEFE) >> 1;
+ count = FFMAX(count, 64);
+ }
} else { // Create gray-scale color palette for bps < 8
count = 1 << avctx->bits_per_coded_sample;
for (i = 0; i < count; i++)
pal[i] = 0xFF000000 | gray2rgb((i * 255) >> avctx->bits_per_coded_sample);
}
+ if (s->masking == MASK_HAS_MASK) {
+ memcpy(pal + (1 << avctx->bits_per_coded_sample), pal, count * 4);
+ for (i = 0; i < count; i++)
+ pal[i] &= 0xFFFFFF;
+ } else if (s->masking == MASK_HAS_TRANSPARENT_COLOR &&
+ s->transparency < 1 << avctx->bits_per_coded_sample)
+ pal[s->transparency] &= 0xFFFFFF;
+ return 0;
+}
+
+/**
+ * Extracts the IFF extra context and updates internal
+ * decoder structures.
+ *
+ * @param avctx the AVCodecContext where to extract extra context to
+ * @param avpkt the AVPacket to extract extra context from or NULL to use avctx
+ * @return >= 0 in case of success, a negative error code otherwise
+ */
+static int extract_header(AVCodecContext *const avctx,
+ 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) {
+ av_log(avctx, AV_LOG_ERROR, "not enough extradata\n");
+ return AVERROR_INVALIDDATA;
+ }
+ palette_size = avctx->extradata_size - AV_RB16(avctx->extradata);
+
+ 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')) {
+ unsigned extra;
+ if (data_size < 40)
+ return AVERROR_INVALIDDATA;
+
+ s->compression = (bytestream2_get_byte(gb) << 8) | (s->compression & 0xFF);
+ bytestream2_skip(gb, 19);
+ extra = bytestream2_get_be32(gb);
+ s->is_short = !(extra & 1);
+ s->is_brush = extra == 2;
+ s->is_interlaced = !!(extra & 0x40);
+ 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;
+
+ 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 if (!avpkt) {
+ buf = avctx->extradata;
+ buf_size = bytestream_get_be16(&buf);
+ if (buf_size <= 1 || palette_size < 0) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Invalid palette size received: %u -> palette data offset: %d\n",
+ buf_size, palette_size);
+ return AVERROR_INVALIDDATA;
+ }
+ }
+
+ if (buf_size >= 41) {
+ s->compression = bytestream_get_byte(&buf);
+ s->bpp = bytestream_get_byte(&buf);
+ s->ham = bytestream_get_byte(&buf);
+ s->flags = bytestream_get_byte(&buf);
+ s->transparency = bytestream_get_be16(&buf);
+ s->masking = bytestream_get_byte(&buf);
+ for (i = 0; i < 16; i++)
+ s->tvdc[i] = bytestream_get_be16(&buf);
+
+ if (s->masking == MASK_HAS_MASK) {
+ if (s->bpp >= 8 && !s->ham) {
+ avctx->pix_fmt = AV_PIX_FMT_RGB32;
+ av_freep(&s->mask_buf);
+ av_freep(&s->mask_palbuf);
+ s->mask_buf = av_malloc((s->planesize * 32) + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!s->mask_buf)
+ return AVERROR(ENOMEM);
+ if (s->bpp > 16) {
+ av_log(avctx, AV_LOG_ERROR, "bpp %d too large for palette\n", s->bpp);
+ av_freep(&s->mask_buf);
+ return AVERROR(ENOMEM);
+ }
+ s->mask_palbuf = av_malloc((2 << s->bpp) * sizeof(uint32_t) + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!s->mask_palbuf) {
+ av_freep(&s->mask_buf);
+ return AVERROR(ENOMEM);
+ }
+ }
+ s->bpp++;
+ } else if (s->masking != MASK_NONE && s->masking != MASK_HAS_TRANSPARENT_COLOR) {
+ av_log(avctx, AV_LOG_ERROR, "Masking not supported\n");
+ return AVERROR_PATCHWELCOME;
+ }
+ if (!s->bpp || s->bpp > 32) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid number of bitplanes: %u\n", s->bpp);
+ return AVERROR_INVALIDDATA;
+ } else if (s->ham >= 8) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid number of hold bits for HAM: %u\n", s->ham);
+ return AVERROR_INVALIDDATA;
+ }
+
+ av_freep(&s->ham_buf);
+ av_freep(&s->ham_palbuf);
+
+ if (s->ham) {
+ int i, count = FFMIN(palette_size / 3, 1 << s->ham);
+ int ham_count;
+ const uint8_t *const palette = avctx->extradata + AV_RB16(avctx->extradata);
+
+ s->ham_buf = av_malloc((s->planesize * 8) + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!s->ham_buf)
+ return AVERROR(ENOMEM);
+
+ ham_count = 8 * (1 << s->ham);
+ s->ham_palbuf = av_malloc((ham_count << !!(s->masking == MASK_HAS_MASK)) * sizeof (uint32_t) + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!s->ham_palbuf) {
+ av_freep(&s->ham_buf);
+ return AVERROR(ENOMEM);
+ }
+
+ if (count) { // HAM with color palette attached
+ // prefill with black and palette and set HAM take direct value mask to zero
+ memset(s->ham_palbuf, 0, (1 << s->ham) * 2 * sizeof (uint32_t));
+ for (i=0; i < count; i++) {
+ s->ham_palbuf[i*2+1] = 0xFF000000 | AV_RL24(palette + i*3);
+ }
+ count = 1 << s->ham;
+ } else { // HAM with grayscale color palette
+ count = 1 << s->ham;
+ for (i=0; i < count; i++) {
+ s->ham_palbuf[i*2] = 0xFF000000; // take direct color value from palette
+ s->ham_palbuf[i*2+1] = 0xFF000000 | av_le2ne32(gray2rgb((i * 255) >> s->ham));
+ }
+ }
+ for (i=0; i < count; i++) {
+ uint32_t tmp = i << (8 - s->ham);
+ tmp |= tmp >> s->ham;
+ s->ham_palbuf[(i+count)*2] = 0xFF00FFFF; // just modify blue color component
+ s->ham_palbuf[(i+count*2)*2] = 0xFFFFFF00; // just modify red color component
+ s->ham_palbuf[(i+count*3)*2] = 0xFFFF00FF; // just modify green color component
+ 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 < ham_count; i++)
+ s->ham_palbuf[(1 << s->bpp) + i] = s->ham_palbuf[i] | 0xFF000000;
+ }
+ }
+ }
+
return 0;
}
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);
return 0;
}
@@ -160,11 +383,29 @@ static av_cold int decode_init(AVCodecContext *avctx)
int err;
if (avctx->bits_per_coded_sample <= 8) {
- avctx->pix_fmt = (avctx->bits_per_coded_sample < 8 ||
- avctx->extradata_size) ? AV_PIX_FMT_PAL8
- : AV_PIX_FMT_GRAY8;
+ int palette_size;
+
+ if (avctx->extradata_size >= 2)
+ palette_size = avctx->extradata_size - AV_RB16(avctx->extradata);
+ else
+ palette_size = 0;
+ avctx->pix_fmt = (avctx->bits_per_coded_sample < 8) ||
+ (avctx->extradata_size >= 2 && palette_size) ? AV_PIX_FMT_PAL8 : AV_PIX_FMT_GRAY8;
} else if (avctx->bits_per_coded_sample <= 32) {
- avctx->pix_fmt = AV_PIX_FMT_BGR32;
+ if (avctx->codec_tag == MKTAG('R', 'G', 'B', '8')) {
+ avctx->pix_fmt = AV_PIX_FMT_RGB32;
+ } else if (avctx->codec_tag == MKTAG('R', 'G', 'B', 'N')) {
+ avctx->pix_fmt = AV_PIX_FMT_RGB444;
+ } else if (avctx->codec_tag != MKTAG('D', 'E', 'E', 'P')) {
+ if (avctx->bits_per_coded_sample == 24) {
+ avctx->pix_fmt = AV_PIX_FMT_0BGR32;
+ } else if (avctx->bits_per_coded_sample == 32) {
+ avctx->pix_fmt = AV_PIX_FMT_BGR32;
+ } else {
+ avpriv_request_sample(avctx, "unknown bits_per_coded_sample");
+ return AVERROR_PATCHWELCOME;
+ }
+ }
} else {
return AVERROR_INVALIDDATA;
}
@@ -172,16 +413,24 @@ static av_cold int decode_init(AVCodecContext *avctx)
if ((err = av_image_check_size(avctx->width, avctx->height, 0, avctx)))
return err;
s->planesize = FFALIGN(avctx->width, 16) >> 3; // Align plane size in bits to word-boundary
- s->planebuf = av_malloc(s->planesize + AV_INPUT_BUFFER_PADDING_SIZE);
+ s->planebuf = av_malloc(s->planesize * avctx->height + AV_INPUT_BUFFER_PADDING_SIZE);
if (!s->planebuf)
return AVERROR(ENOMEM);
- s->frame = av_frame_alloc();
- if (!s->frame) {
- decode_end(avctx);
- return AVERROR(ENOMEM);
+ s->bpp = avctx->bits_per_coded_sample;
+
+ 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 = av_calloc(256, sizeof(*s->pal));
+ if (!s->video[0] || !s->video[1] || !s->pal)
+ return AVERROR(ENOMEM);
}
+ if ((err = extract_header(avctx, NULL)) < 0)
+ return err;
+
return 0;
}
@@ -195,6 +444,10 @@ static av_cold int decode_init(AVCodecContext *avctx)
static void decodeplane8(uint8_t *dst, const uint8_t *buf, int buf_size, int plane)
{
const uint64_t *lut = plane8_lut[plane];
+ if (plane >= 8) {
+ av_log(NULL, AV_LOG_WARNING, "Ignoring extra planes beyond 8\n");
+ return;
+ }
do {
uint64_t v = AV_RN64A(dst) | lut[*buf++];
AV_WN64A(dst, v);
@@ -227,6 +480,47 @@ static void decodeplane32(uint32_t *dst, const uint8_t *buf, int buf_size, int p
} while (--buf_size);
}
+#define DECODE_HAM_PLANE32(x) \
+ first = buf[x] << 1; \
+ second = buf[(x)+1] << 1; \
+ delta &= pal[first++]; \
+ delta |= pal[first]; \
+ dst[x] = delta; \
+ delta &= pal[second++]; \
+ delta |= pal[second]; \
+ dst[(x)+1] = delta
+
+/**
+ * Converts one line of HAM6/8-encoded chunky buffer to 24bpp.
+ *
+ * @param dst the destination 24bpp buffer
+ * @param buf the source 8bpp chunky buffer
+ * @param pal the HAM decode table
+ * @param buf_size the plane size in bytes
+ */
+static void decode_ham_plane32(uint32_t *dst, const uint8_t *buf,
+ const uint32_t *const pal, unsigned buf_size)
+{
+ uint32_t delta = pal[1]; /* first palette entry */
+ do {
+ uint32_t first, second;
+ DECODE_HAM_PLANE32(0);
+ DECODE_HAM_PLANE32(2);
+ DECODE_HAM_PLANE32(4);
+ DECODE_HAM_PLANE32(6);
+ buf += 8;
+ dst += 8;
+ } while (--buf_size);
+}
+
+static void lookup_pal_indicies(uint32_t *dst, const uint32_t *buf,
+ const uint32_t *const pal, unsigned width)
+{
+ do {
+ *dst++ = pal[*buf++];
+ } while (--width);
+}
+
/**
* Decode one complete byterun1 encoded line.
*
@@ -237,162 +531,1353 @@ static void decodeplane32(uint32_t *dst, const uint8_t *buf, int buf_size, int p
* @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 = value + 1;
- memcpy(dst + x, buf, FFMIN3(length, dst_size - x, buf_end - buf));
- buf += length;
+ length = FFMIN3(value + 1, dst_size - x, bytestream2_get_bytes_left(gb));
+ bytestream2_get_buffer(gb, dst + x, length);
+ if (length < value + 1)
+ bytestream2_skip(gb, value + 1 - length);
} else if (value > -128) {
- length = -value + 1;
- memset(dst + x, *buf++, FFMIN(length, dst_size - x));
+ length = FFMIN(-value + 1, dst_size - x);
+ memset(dst + x, bytestream2_get_byte(gb), length);
} else { // noop
continue;
}
x += length;
}
- return buf - buf_start;
+ if (x < dst_size) {
+ av_log(NULL, AV_LOG_WARNING, "decode_byterun ended before plane size\n");
+ memset(dst+x, 0, dst_size - x);
+ }
+ return bytestream2_tell(gb);
}
-static int decode_frame_ilbm(AVCodecContext *avctx,
- void *data, int *got_frame,
- AVPacket *avpkt)
+static int decode_byterun2(uint8_t *dst, int height, int line_size,
+ GetByteContext *gb)
{
- IffContext *s = avctx->priv_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 cmds;
+ unsigned count;
+ int i, y_pos = 0, x_pos = 0;
- if ((res = ff_reget_buffer(avctx, s->frame)) < 0)
- return res;
+ if (bytestream2_get_be32(gb) != MKBETAG('V', 'D', 'A', 'T'))
+ return 0;
- if (!s->init && avctx->bits_per_coded_sample <= 8 &&
- avctx->pix_fmt != AV_PIX_FMT_GRAY8) {
- if ((res = cmap_read_palette(avctx, (uint32_t *)s->frame->data[1])) < 0)
- return res;
+ bytestream2_skip(gb, 4);
+ count = bytestream2_get_be16(gb) - 2;
+ if (bytestream2_get_bytes_left(gb) < count)
+ return 0;
+
+ bytestream2_init(&cmds, gb->buffer, count);
+ bytestream2_skip(gb, count);
+
+ for (i = 0; i < count && x_pos < line_size; i++) {
+ int8_t cmd = bytestream2_get_byte(&cmds);
+ int l, r;
+
+ if (cmd == 0) {
+ l = bytestream2_get_be16(gb);
+ while (l-- > 0 && x_pos < line_size) {
+ dst[x_pos + y_pos * line_size ] = bytestream2_get_byte(gb);
+ dst[x_pos + y_pos++ * line_size + 1] = bytestream2_get_byte(gb);
+ if (y_pos >= height) {
+ y_pos = 0;
+ x_pos += 2;
+ }
+ }
+ } else if (cmd < 0) {
+ l = -cmd;
+ while (l-- > 0 && x_pos < line_size) {
+ dst[x_pos + y_pos * line_size ] = bytestream2_get_byte(gb);
+ dst[x_pos + y_pos++ * line_size + 1] = bytestream2_get_byte(gb);
+ if (y_pos >= height) {
+ y_pos = 0;
+ x_pos += 2;
+ }
+ }
+ } else if (cmd == 1) {
+ l = bytestream2_get_be16(gb);
+ r = bytestream2_get_be16(gb);
+ while (l-- > 0 && x_pos < line_size) {
+ dst[x_pos + y_pos * line_size ] = r >> 8;
+ dst[x_pos + y_pos++ * line_size + 1] = r & 0xFF;
+ if (y_pos >= height) {
+ y_pos = 0;
+ x_pos += 2;
+ }
+ }
+ } else {
+ l = cmd;
+ r = bytestream2_get_be16(gb);
+ while (l-- > 0 && x_pos < line_size) {
+ dst[x_pos + y_pos * line_size ] = r >> 8;
+ dst[x_pos + y_pos++ * line_size + 1] = r & 0xFF;
+ if (y_pos >= height) {
+ y_pos = 0;
+ x_pos += 2;
+ }
+ }
+ }
}
- s->init = 1;
- if (avctx->codec_tag == MKTAG('I', 'L', 'B', 'M')) { // interleaved
- 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]];
- memset(row, 0, avctx->width);
- for (plane = 0; plane < avctx->bits_per_coded_sample && buf < buf_end;
- plane++) {
- decodeplane8(row, buf, FFMIN(s->planesize, buf_end - buf), plane);
- buf += s->planesize;
+ return bytestream2_tell(gb);
+}
+
+#define DECODE_RGBX_COMMON(type) \
+ if (!length) { \
+ length = bytestream2_get_byte(gb); \
+ if (!length) { \
+ length = bytestream2_get_be16(gb); \
+ if (!length) \
+ return; \
+ } \
+ } \
+ for (i = 0; i < length; i++) { \
+ *(type *)(dst + y*linesize + x * sizeof(type)) = pixel; \
+ x += 1; \
+ if (x >= width) { \
+ y += 1; \
+ if (y >= height) \
+ return; \
+ x = 0; \
+ } \
+ }
+
+/**
+ * Decode RGB8 buffer
+ * @param[out] dst Destination buffer
+ * @param width Width of destination buffer (pixels)
+ * @param height Height of destination buffer (pixels)
+ * @param linesize Line size of destination buffer (bytes)
+ */
+static void decode_rgb8(GetByteContext *gb, uint8_t *dst, int width, int height, int linesize)
+{
+ int x = 0, y = 0, i, length;
+ while (bytestream2_get_bytes_left(gb) >= 4) {
+ uint32_t pixel = 0xFF000000 | bytestream2_get_be24(gb);
+ length = bytestream2_get_byte(gb) & 0x7F;
+ DECODE_RGBX_COMMON(uint32_t)
+ }
+}
+
+/**
+ * Decode RGBN buffer
+ * @param[out] dst Destination buffer
+ * @param width Width of destination buffer (pixels)
+ * @param height Height of destination buffer (pixels)
+ * @param linesize Line size of destination buffer (bytes)
+ */
+static void decode_rgbn(GetByteContext *gb, uint8_t *dst, int width, int height, int linesize)
+{
+ int x = 0, y = 0, i, length;
+ while (bytestream2_get_bytes_left(gb) >= 2) {
+ uint32_t pixel = bytestream2_get_be16u(gb);
+ length = pixel & 0x7;
+ pixel >>= 4;
+ DECODE_RGBX_COMMON(uint16_t)
+ }
+}
+
+/**
+ * Decode DEEP RLE 32-bit buffer
+ * @param[out] dst Destination buffer
+ * @param[in] src Source buffer
+ * @param src_size Source buffer size (bytes)
+ * @param width Width of destination buffer (pixels)
+ * @param height Height of destination buffer (pixels)
+ * @param linesize Line size of destination buffer (bytes)
+ */
+static void decode_deep_rle32(uint8_t *dst, const uint8_t *src, int src_size, int width, int height, int linesize)
+{
+ const uint8_t *src_end = src + src_size;
+ int x = 0, y = 0, i;
+ while (src + 5 <= src_end) {
+ int opcode;
+ opcode = *(int8_t *)src++;
+ if (opcode >= 0) {
+ int size = opcode + 1;
+ for (i = 0; i < size; i++) {
+ int length = FFMIN(size - i, width);
+ memcpy(dst + y*linesize + x * 4, src, length * 4);
+ src += length * 4;
+ x += length;
+ i += length;
+ if (x >= width) {
+ x = 0;
+ y += 1;
+ if (y >= height)
+ return;
}
}
- } else { // AV_PIX_FMT_BGR32
- for (y = 0; y < avctx->height; y++) {
- uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]];
- memset(row, 0, avctx->width << 2);
- for (plane = 0; plane < avctx->bits_per_coded_sample && buf < buf_end;
- plane++) {
- decodeplane32((uint32_t *)row, buf,
- FFMIN(s->planesize, buf_end - buf), plane);
- buf += s->planesize;
+ } else {
+ int size = -opcode + 1;
+ uint32_t pixel = AV_RN32(src);
+ for (i = 0; i < size; i++) {
+ *(uint32_t *)(dst + y*linesize + x * 4) = pixel;
+ x += 1;
+ if (x >= width) {
+ x = 0;
+ y += 1;
+ if (y >= height)
+ return;
}
}
+ src += 4;
+ }
+ }
+}
+
+/**
+ * Decode DEEP TVDC 32-bit buffer
+ * @param[out] dst Destination buffer
+ * @param[in] src Source buffer
+ * @param src_size Source buffer size (bytes)
+ * @param width Width of destination buffer (pixels)
+ * @param height Height of destination buffer (pixels)
+ * @param linesize Line size of destination buffer (bytes)
+ * @param[int] tvdc TVDC lookup table
+ */
+static void decode_deep_tvdc32(uint8_t *dst, const uint8_t *src, int src_size, int width, int height, int linesize, const int16_t *tvdc)
+{
+ int x = 0, y = 0, plane = 0;
+ int8_t pixel = 0;
+ int i, j;
+
+ for (i = 0; i < src_size * 2;) {
+#define GETNIBBLE ((i & 1) ? (src[i>>1] & 0xF) : (src[i>>1] >> 4))
+ int d = tvdc[GETNIBBLE];
+ i++;
+ if (d) {
+ pixel += d;
+ dst[y * linesize + x*4 + plane] = pixel;
+ x++;
+ } else {
+ if (i >= src_size * 2)
+ return;
+ d = GETNIBBLE + 1;
+ i++;
+ d = FFMIN(d, width - x);
+ for (j = 0; j < d; j++) {
+ dst[y * linesize + x*4 + plane] = pixel;
+ x++;
+ }
}
- } else if (avctx->pix_fmt == AV_PIX_FMT_PAL8 || avctx->pix_fmt == AV_PIX_FMT_GRAY8) { // IFF-PBM
- for (y = 0; y < avctx->height && buf < buf_end; y++) {
- uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]];
- memcpy(row, buf, FFMIN(avctx->width, buf_end - buf));
- buf += avctx->width + (avctx->width % 2); // padding if odd
+ if (x >= width) {
+ plane++;
+ if (plane >= 4) {
+ y++;
+ if (y >= height)
+ return;
+ plane = 0;
+ }
+ x = 0;
+ pixel = 0;
+ i = (i + 1) & ~1;
}
}
+}
- if ((res = av_frame_ref(data, s->frame)) < 0)
- return res;
+static void decode_short_horizontal_delta(uint8_t *dst,
+ const uint8_t *buf, const uint8_t *buf_end,
+ int w, int bpp, int dst_size)
+{
+ int planepitch = FFALIGN(w, 16) >> 3;
+ int pitch = planepitch * bpp;
+ GetByteContext ptrs, gb;
+ PutByteContext pb;
+ unsigned ofssrc, pos;
+ int i, k;
- *got_frame = 1;
+ bytestream2_init(&ptrs, buf, buf_end - buf);
+ bytestream2_init_writer(&pb, dst, dst_size);
- return buf_size;
+ for (k = 0; k < bpp; k++) {
+ ofssrc = bytestream2_get_be32(&ptrs);
+ pos = 0;
+
+ if (!ofssrc)
+ continue;
+
+ if (ofssrc >= buf_end - buf)
+ continue;
+
+ bytestream2_init(&gb, buf + ofssrc, buf_end - (buf + ofssrc));
+ while (bytestream2_peek_be16(&gb) != 0xFFFF && bytestream2_get_bytes_left(&gb) > 3) {
+ int16_t offset = bytestream2_get_be16(&gb);
+ unsigned noffset;
+
+ if (offset >= 0) {
+ unsigned data = bytestream2_get_be16(&gb);
+
+ pos += offset * 2;
+ noffset = (pos / planepitch) * pitch + (pos % planepitch) + k * planepitch;
+ bytestream2_seek_p(&pb, noffset, SEEK_SET);
+ bytestream2_put_be16(&pb, data);
+ } else {
+ uint16_t count = bytestream2_get_be16(&gb);
+
+ pos += 2 * -(offset + 2);
+ for (i = 0; i < count; i++) {
+ uint16_t data = bytestream2_get_be16(&gb);
+
+ pos += 2;
+ noffset = (pos / planepitch) * pitch + (pos % planepitch) + k * planepitch;
+ bytestream2_seek_p(&pb, noffset, SEEK_SET);
+ bytestream2_put_be16(&pb, data);
+ }
+ }
+ }
+ }
+}
+
+static void decode_byte_vertical_delta(uint8_t *dst,
+ const uint8_t *buf, const uint8_t *buf_end,
+ int w, int xor, 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);
+ if (xor && ofsdst < dst_size) {
+ bytestream2_put_byte(&pb, dst[ofsdst] ^ x);
+ } else {
+ 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);
+ if (xor && ofsdst < dst_size) {
+ bytestream2_put_byte(&pb, dst[ofsdst] ^ bytestream2_get_byte(&gb));
+ } else {
+ 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 *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 (cols * bpp == 0 || bytestream2_get_bytes_left(&gb) < cols * bpp) {
+ av_log(NULL, AV_LOG_ERROR, "cols*bpp is invalid (%"PRId32"*%d)", cols, bpp);
+ return;
+ }
+
+ if (kludge_j)
+ offset = ((offset / (320 / 8)) * pitch) + (offset % (320 / 8)) - kludge_j;
+ else
+ offset = ((offset / planepitch_byte) * pitch) + (offset % planepitch_byte);
+
+ for (b = 0; b < cols; b++) {
+ for (d = 0; d < bpp; d++) {
+ uint8_t value = bytestream2_get_byte(&gb);
+
+ if (offset >= dst_size)
+ return;
+ ptr = dst + offset;
+
+ if (flag)
+ ptr[0] ^= value;
+ else
+ ptr[0] = value;
+
+ offset += planepitch;
+ }
+ }
+ 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++) {
+ unsigned noffset = offset + (r * pitch) + d * planepitch;
+
+ if (!bytes || bytestream2_get_bytes_left(&gb) < bytes) {
+ av_log(NULL, AV_LOG_ERROR, "bytes %"PRId32" is invalid", bytes);
+ return;
+ }
+
+ for (b = 0; b < bytes; b++) {
+ uint8_t value = bytestream2_get_byte(&gb);
+
+ if (noffset >= dst_size)
+ return;
+ ptr = dst + noffset;
+
+ if (flag)
+ ptr[0] ^= value;
+ else
+ ptr[0] = value;
+
+ noffset++;
+ }
+ }
+ }
+ if ((rows * bytes * bpp) & 1)
+ bytestream2_skip(&gb, 1);
+ }
+ break;
+ default:
+ return;
+ }
+ }
}
-static int decode_frame_byterun1(AVCodecContext *avctx,
- void *data, int *got_frame,
- AVPacket *avpkt)
+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_d(uint8_t *dst,
+ const uint8_t *buf, const uint8_t *buf_end,
+ int w, int flag, int bpp, int dst_size)
+{
+ int planepitch = FFALIGN(w, 16) >> 3;
+ int pitch = planepitch * bpp;
+ int planepitch_byte = (w + 7) / 8;
+ unsigned entries, ofssrc;
+ GetByteContext gb, ptrs;
+ PutByteContext pb;
+ int k;
+
+ if (buf_end - buf <= 4 * bpp)
+ return;
+
+ bytestream2_init_writer(&pb, dst, dst_size);
+ bytestream2_init(&ptrs, buf, bpp * 4);
+
+ 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));
+
+ entries = bytestream2_get_be32(&gb);
+ while (entries && bytestream2_get_bytes_left(&gb) >= 8) {
+ int32_t opcode = bytestream2_get_be32(&gb);
+ unsigned offset = bytestream2_get_be32(&gb);
+
+ bytestream2_seek_p(&pb, (offset / planepitch_byte) * pitch + (offset % planepitch_byte) + k * planepitch, SEEK_SET);
+ if (opcode >= 0) {
+ uint32_t x = bytestream2_get_be32(&gb);
+ while (opcode && bytestream2_get_bytes_left_p(&pb) > 0) {
+ bytestream2_put_be32(&pb, x);
+ bytestream2_skip_p(&pb, pitch - 4);
+ opcode--;
+ }
+ } else {
+ opcode = -opcode;
+ while (opcode && bytestream2_get_bytes_left(&gb) > 0) {
+ bytestream2_put_be32(&pb, bytestream2_get_be32(&gb));
+ bytestream2_skip_p(&pb, pitch - 4);
+ opcode--;
+ }
+ }
+ entries--;
+ }
+ }
+}
+
+static void decode_delta_e(uint8_t *dst,
+ const uint8_t *buf, const uint8_t *buf_end,
+ int w, int flag, int bpp, int dst_size)
+{
+ int planepitch = FFALIGN(w, 16) >> 3;
+ int pitch = planepitch * bpp;
+ int planepitch_byte = (w + 7) / 8;
+ unsigned entries, ofssrc;
+ GetByteContext gb, ptrs;
+ PutByteContext pb;
+ int k;
+
+ if (buf_end - buf <= 4 * bpp)
+ return;
+
+ bytestream2_init_writer(&pb, dst, dst_size);
+ bytestream2_init(&ptrs, buf, bpp * 4);
+
+ 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));
+
+ entries = bytestream2_get_be16(&gb);
+ while (entries && bytestream2_get_bytes_left(&gb) >= 6) {
+ int16_t opcode = bytestream2_get_be16(&gb);
+ unsigned offset = bytestream2_get_be32(&gb);
+
+ bytestream2_seek_p(&pb, (offset / planepitch_byte) * pitch + (offset % planepitch_byte) + k * planepitch, SEEK_SET);
+ if (opcode >= 0) {
+ uint16_t x = bytestream2_get_be16(&gb);
+ while (opcode && bytestream2_get_bytes_left_p(&pb) > 0) {
+ bytestream2_put_be16(&pb, x);
+ bytestream2_skip_p(&pb, pitch - 2);
+ opcode--;
+ }
+ } else {
+ opcode = -opcode;
+ while (opcode && bytestream2_get_bytes_left(&gb) > 0) {
+ bytestream2_put_be16(&pb, bytestream2_get_be16(&gb));
+ bytestream2_skip_p(&pb, pitch - 2);
+ opcode--;
+ }
+ }
+ entries--;
+ }
+ }
+}
+
+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 && bytestream2_get_bytes_left(&ogb) >= 4) {
+ uint32_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) {
+ if (bytestream2_get_bytes_left(&dgb) < 2)
+ break;
+ 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 {
+ if (bytestream2_get_bytes_left(&dgb) < 2*cnt)
+ break;
+ 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 0x%0x, bpp %i, ham %i, interlaced %i)", s->compression, s->bpp, s->ham, s->is_interlaced);
+ return AVERROR_INVALIDDATA;
+}
+
+static int decode_frame(AVCodecContext *avctx,
+ void *data, int *got_frame,
+ AVPacket *avpkt)
{
IffContext *s = avctx->priv_data;
+ 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 = &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_GRAY8) {
- if ((res = cmap_read_palette(avctx, (uint32_t *)s->frame->data[1])) < 0)
+ avctx->pix_fmt == AV_PIX_FMT_PAL8) {
+ 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) {
+ if ((res = cmap_read_palette(avctx, s->mask_palbuf)) < 0)
return res;
}
s->init = 1;
- if (avctx->codec_tag == MKTAG('I', 'L', 'B', 'M')) { // interleaved
+ if (s->compression <= 0xff && (avctx->codec_tag == MKTAG('A', 'N', 'I', 'M'))) {
+ if (avctx->pix_fmt == AV_PIX_FMT_PAL8)
+ memcpy(s->pal, s->frame->data[1], 256 * 4);
+ }
+
+ switch (s->compression) {
+ 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(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 = &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(frame->data[0], 0, avctx->height * frame->linesize[0]);
+ 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++) {
+ const uint8_t * start = buf + (plane * avctx->height + y) * s->planesize;
+ if (start >= buf_end)
+ break;
+ decodeplane8(s->ham_buf, start, FFMIN(s->planesize, buf_end - start), plane);
+ }
+ 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')) {
+ 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 = &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) {
+ for (x = 0; x < avctx->width; x++)
+ 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
+ avctx->codec_tag == MKTAG('A', 'N', 'I', 'M')) {
+ if (avctx->codec_tag == MKTAG('A', 'N', 'I', 'M'))
+ memcpy(s->video[0], buf, FFMIN(buf_end - buf, s->video_size));
+ 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 = &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);
+ buf += s->planesize;
+ }
+ }
+ } else if (s->ham) { // HAM to AV_PIX_FMT_BGR32
+ 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 && buf < buf_end; plane++) {
+ decodeplane8(s->ham_buf, buf, FFMIN(s->planesize, buf_end - buf), plane);
+ buf += s->planesize;
+ }
+ 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 = &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,
+ FFMIN(s->planesize, buf_end - buf), plane);
+ buf += s->planesize;
+ }
+ }
+ }
+ } 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 = &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 = &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);
+ }
+ } else
+ return unsupported(avctx);
+ } else {
+ return unsupported(avctx);
+ }
+ break;
+ 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 = &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, 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 = &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, 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 = &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, 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 = &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, gb);
+ decodeplane32((uint32_t *)row, s->planebuf, s->planesize, plane);
+ }
+ }
+ }
+ } 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 = &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 = &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(frame->data[0], buf, buf_size, avctx->width, avctx->height, frame->linesize[0]);
+ else
+ return unsupported(avctx);
+ } else 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(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 = &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(frame->data[0], 0, avctx->height * frame->linesize[0]);
+ 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++) {
+ const uint8_t * start = buf + (plane * avctx->height + y) * s->planesize;
+ if (start >= buf_end)
+ break;
+ decodeplane8(s->ham_buf, start, FFMIN(s->planesize, buf_end - start), plane);
+ }
+ decode_ham_plane32((uint32_t *)row, s->ham_buf, s->ham_palbuf, s->planesize);
+ }
+ } else {
+ return unsupported(avctx);
+ }
+ } else {
+ return unsupported(avctx);
+ }
+ break;
+ case 0x2:
+ if (avctx->codec_tag == MKTAG('I', 'L', 'B', 'M') && avctx->pix_fmt == AV_PIX_FMT_PAL8) {
+ for (plane = 0; plane < s->bpp; plane++) {
+ decode_byterun2(s->planebuf, avctx->height, s->planesize, gb);
+ for (y = 0; y < avctx->height; y++) {
+ uint8_t *row = &frame->data[0][y * frame->linesize[0]];
+ decodeplane8(row, s->planebuf + s->planesize * y, s->planesize, plane);
+ }
+ }
+ } else {
+ return unsupported(avctx);
+ }
+ break;
+ case 0x4:
+ if (avctx->codec_tag == MKTAG('R', 'G', 'B', '8') && avctx->pix_fmt == AV_PIX_FMT_RGB32)
+ 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, frame->data[0], avctx->width, avctx->height, frame->linesize[0]);
+ else
+ return unsupported(avctx);
+ break;
+ case 0x5:
+ if (avctx->codec_tag == MKTAG('D', 'E', 'E', 'P')) {
+ if (av_get_bits_per_pixel(desc) == 32)
+ 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 0x300:
+ case 0x301:
+ decode_short_horizontal_delta(s->video[0], buf, buf_end, avctx->width, s->bpp, s->video_size);
+ break;
+ case 0x500:
+ case 0x501:
+ decode_byte_vertical_delta(s->video[0], buf, buf_end, avctx->width, s->is_brush, 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 0x6400:
+ case 0x6401:
+ if (s->is_interlaced)
+ return unsupported(avctx);
+ decode_delta_d(s->video[0], buf, buf_end, avctx->width, s->is_interlaced, s->bpp, s->video_size);
+ break;
+ case 0x6500:
+ case 0x6501:
+ if (s->is_interlaced)
+ return unsupported(avctx);
+ decode_delta_e(s->video[0], buf, buf_end, avctx->width, s->is_interlaced, 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 (s->compression <= 0xff && (avctx->codec_tag == MKTAG('A', 'N', 'I', 'M'))) {
+ memcpy(s->video[1], s->video[0], s->video_size);
+ }
+
+ 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 = &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 < avctx->bits_per_coded_sample; plane++) {
- buf += decode_byterun(s->planebuf, s->planesize, buf, buf_end);
- decodeplane8(row, s->planebuf, s->planesize, plane);
+ for (plane = 0; plane < s->bpp; plane++) {
+ decodeplane8(row, buf, s->planesize, plane);
+ buf += s->planesize;
}
}
- } else { // AV_PIX_FMT_BGR32
+ memcpy(frame->data[1], s->pal, 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[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 = &s->frame->data[0][y * s->frame->linesize[0]];
- memset(row, 0, avctx->width << 2);
- for (plane = 0; plane < avctx->bits_per_coded_sample; plane++) {
- buf += decode_byterun(s->planebuf, s->planesize, buf, buf_end);
- decodeplane32((uint32_t *)row, s->planebuf, s->planesize, plane);
+ 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);
}
- } else {
- 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);
+
+ if (!s->is_brush) {
+ FFSWAP(uint8_t *, s->video[0], s->video[1]);
}
}
- if ((res = av_frame_ref(data, s->frame)) < 0)
- return res;
+ 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;
return buf_size;
}
+#if CONFIG_IFF_ILBM_DECODER
AVCodec ff_iff_ilbm_decoder = {
- .name = "iff_ilbm",
- .long_name = NULL_IF_CONFIG_SMALL("IFF ILBM"),
+ .name = "iff",
+ .long_name = NULL_IF_CONFIG_SMALL("IFF ACBM/ANIM/DEEP/ILBM/PBM/RGB8/RGBN"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_IFF_ILBM,
.priv_data_size = sizeof(IffContext),
.init = decode_init,
.close = decode_end,
- .decode = decode_frame_ilbm,
- .capabilities = AV_CODEC_CAP_DR1,
-};
-
-AVCodec ff_iff_byterun1_decoder = {
- .name = "iff_byterun1",
- .long_name = NULL_IF_CONFIG_SMALL("IFF ByteRun1"),
- .type = AVMEDIA_TYPE_VIDEO,
- .id = AV_CODEC_ID_IFF_BYTERUN1,
- .priv_data_size = sizeof(IffContext),
- .init = decode_init,
- .close = decode_end,
- .decode = decode_frame_byterun1,
+ .decode = decode_frame,
.capabilities = AV_CODEC_CAP_DR1,
};
+#endif