Hi, patch attached.
From c7ff2e61fee53a9f02c66042c96ad622f8d6bf23 Mon Sep 17 00:00:00 2001 From: Paul B Mahol <one...@gmail.com> Date: Fri, 19 Feb 2016 14:35:53 +0100 Subject: [PATCH] IFF ANIM support
Currently only most common compression implemented. Signed-off-by: Paul B Mahol <one...@gmail.com> --- libavcodec/iff.c | 334 ++++++++++++++++++++++++++++++++++---------- libavformat/iff.c | 60 +++++--- tests/ref/fate/iff-byterun1 | 4 +- tests/ref/fate/iff-ilbm | 4 +- 4 files changed, 308 insertions(+), 94 deletions(-) diff --git a/libavcodec/iff.c b/libavcodec/iff.c index 49df17c..c766ab4 100644 --- a/libavcodec/iff.c +++ b/libavcodec/iff.c @@ -1,5 +1,5 @@ /* - * IFF ACBM/DEEP/ILBM/PBM bitmap decoder + * IFF ACBM/ANIM/DEEP/ILBM/PBM bitmap decoder * Copyright (c) 2010 Peter Ross <pr...@xvid.org> * Copyright (c) 2010 Sebastian Vater <cdgs.ba...@googlemail.com> * @@ -22,7 +22,7 @@ /** * @file - * IFF ACBM/DEEP/ILBM/PBM bitmap decoder + * IFF ACBM/ANIM/DEEP/ILBM/PBM bitmap decoder */ #include <stdint.h> @@ -30,7 +30,6 @@ #include "libavutil/imgutils.h" #include "bytestream.h" #include "avcodec.h" -#include "get_bits.h" #include "internal.h" // TODO: masking bits @@ -57,6 +56,11 @@ typedef struct IffContext { unsigned masking; ///< TODO: masking method used int init; // 1 if buffer and palette data already initialized, 0 otherwise int16_t tvdc[16]; ///< TVDC lookup table + GetByteContext gb; + uint8_t *video[2]; + unsigned video_size; + uint32_t *pal[2]; + int first; } IffContext; #define LUT8_PART(plane, v) \ @@ -191,7 +195,7 @@ static int cmap_read_palette(AVCodecContext *avctx, uint32_t *pal) static int extract_header(AVCodecContext *const avctx, const AVPacket *const avpkt) { const uint8_t *buf; - unsigned buf_size; + unsigned buf_size = 0; IffContext *s = avctx->priv_data; int i, palette_size; @@ -201,20 +205,54 @@ static int extract_header(AVCodecContext *const avctx, } palette_size = avctx->extradata_size - AV_RB16(avctx->extradata); - if (avpkt) { - int image_size; - if (avpkt->size < 2) - return AVERROR_INVALIDDATA; - image_size = avpkt->size - AV_RB16(avpkt->data); - buf = avpkt->data; - buf_size = bytestream_get_be16(&buf); - if (buf_size <= 1 || image_size <= 1) { - av_log(avctx, AV_LOG_ERROR, - "Invalid image size received: %u -> image data offset: %d\n", - buf_size, image_size); - return AVERROR_INVALIDDATA; + if (avpkt && avctx->codec_tag == MKTAG('A', 'N', 'I', 'M')) { + uint32_t chunk_id; + uint64_t data_size; + int have_bmhd = 0; + 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')) { + have_bmhd = 1; + bytestream2_skip(gb, data_size); + } else if (chunk_id == MKTAG('A', 'N', 'H', 'D')) { + if (data_size != 40) + return AVERROR_INVALIDDATA; + + if (!have_bmhd) { + s->compression = (bytestream2_get_byte(gb) << 8) | (s->compression & 0xFF); + data_size--; + } + bytestream2_skip(gb, data_size); + } else if (chunk_id == MKTAG('D', 'L', 'T', 'A') || + chunk_id == MKTAG('B', 'O', 'D', 'Y')) { + break; + } else if (chunk_id == MKTAG('C', 'M', 'A', 'P')) { + int count = data_size / 3; + uint32_t *pal = s->pal[0]; + + if (s->ham) { + if (count > (1 << (s->ham))) + return AVERROR_INVALIDDATA; + + for (i = 0; i < count; i++) + pal[i] = 0xFF000000 | bytestream2_get_le24(gb); + } else { + if (count > 256) + return AVERROR_INVALIDDATA; + + for (i = 0; i < count; i++) + pal[i] = 0xFF000000 | bytestream2_get_be24(gb); + } + } else { + bytestream2_skip(gb, data_size); + } } - } else { + } else if (!avpkt) { buf = avctx->extradata; buf_size = bytestream_get_be16(&buf); if (buf_size <= 1 || palette_size < 0) { @@ -323,10 +361,13 @@ static int extract_header(AVCodecContext *const avctx, static av_cold int decode_end(AVCodecContext *avctx) { IffContext *s = avctx->priv_data; - av_frame_free(&s->frame); av_freep(&s->planebuf); av_freep(&s->ham_buf); av_freep(&s->ham_palbuf); + av_freep(&s->video[0]); + av_freep(&s->video[1]); + av_freep(&s->pal[0]); + av_freep(&s->pal[1]); return 0; } @@ -371,10 +412,16 @@ static av_cold int decode_init(AVCodecContext *avctx) return AVERROR(ENOMEM); s->bpp = avctx->bits_per_coded_sample; - s->frame = av_frame_alloc(); - if (!s->frame) { - decode_end(avctx); - return AVERROR(ENOMEM); + + if (avctx->codec_tag == MKTAG('A', 'N', 'I', 'M')) { + s->video_size = FFALIGN(avctx->width, 2) * avctx->height * s->bpp; + s->video[0] = av_calloc(FFALIGN(avctx->width, 2) * avctx->height, s->bpp); + s->video[1] = av_calloc(FFALIGN(avctx->width, 2) * avctx->height, s->bpp); + s->pal[0] = av_calloc(256, sizeof(*s->pal[0])); + s->pal[1] = av_calloc(256, sizeof(*s->pal[1])); + if (!s->video[0] || !s->video[1] || !s->pal[0] || !s->pal[1]) + return AVERROR(ENOMEM); + s->first = 1; } if ((err = extract_header(avctx, NULL)) < 0) @@ -480,20 +527,18 @@ static void lookup_pal_indicies(uint32_t *dst, const uint32_t *buf, * @return number of consumed bytes in byterun1 compressed bitstream */ static int decode_byterun(uint8_t *dst, int dst_size, - const uint8_t *buf, const uint8_t *const buf_end) + GetByteContext *gb) { - const uint8_t *const buf_start = buf; unsigned x; - for (x = 0; x < dst_size && buf < buf_end;) { + for (x = 0; x < dst_size && bytestream2_get_bytes_left(gb) > 0;) { unsigned length; - const int8_t value = *buf++; + const int8_t value = bytestream2_get_byte(gb); if (value >= 0) { - length = FFMIN3(value + 1, dst_size - x, buf_end - buf); - memcpy(dst + x, buf, length); - buf += length; + length = FFMIN3(value + 1, dst_size - x, bytestream2_get_bytes_left(gb)); + bytestream2_get_buffer(gb, dst + x, length); } else if (value > -128) { length = FFMIN(-value + 1, dst_size - x); - memset(dst + x, *buf++, length); + memset(dst + x, bytestream2_get_byte(gb), length); } else { // noop continue; } @@ -503,7 +548,7 @@ static int decode_byterun(uint8_t *dst, int dst_size, av_log(NULL, AV_LOG_WARNING, "decode_byterun ended before plane size\n"); memset(dst+x, 0, dst_size - x); } - return buf - buf_start; + return bytestream2_tell(gb); } #define DECODE_RGBX_COMMON(type) \ @@ -660,10 +705,65 @@ 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 h, int bpp) +{ + int ncolumns = ((w + 15) / 16) * 2; + int dstpitch = ncolumns * bpp; + unsigned ofsdst, ofssrc, opcode, x; + GetByteContext ptrs, gb; + int i, j, k; + + bytestream2_init(&ptrs, buf, buf_end - buf); + + 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) { + dst[ofsdst] = x; + ofsdst += dstpitch; + opcode--; + } + } else if (opcode < 0x80) { + ofsdst += opcode * dstpitch; + } else { + opcode &= 0x7f; + + while (opcode) { + dst[ofsdst] = bytestream2_get_byte(&gb); + ofsdst += dstpitch; + opcode--; + } + } + i--; + } + } + } +} + static int unsupported(AVCodecContext *avctx) { IffContext *s = avctx->priv_data; - avpriv_request_sample(avctx, "bitmap (compression %i, bpp %i, ham %i)", s->compression, s->bpp, s->ham); + avpriv_request_sample(avctx, "bitmap (compression 0x%0x, bpp %i, ham %i)", s->compression, s->bpp, s->ham); return AVERROR_INVALIDDATA; } @@ -672,23 +772,30 @@ static int decode_frame(AVCodecContext *avctx, AVPacket *avpkt) { IffContext *s = avctx->priv_data; - const uint8_t *buf = avpkt->size >= 2 ? avpkt->data + AV_RB16(avpkt->data) : NULL; - const int buf_size = avpkt->size >= 2 ? avpkt->size - AV_RB16(avpkt->data) : 0; + AVFrame *frame = data; + const uint8_t *buf = avpkt->data; + int buf_size = avpkt->size; const uint8_t *buf_end = buf + buf_size; int y, plane, res; - GetByteContext gb; + GetByteContext *gb = &s->gb; const AVPixFmtDescriptor *desc; + bytestream2_init(gb, avpkt->data, avpkt->size); + if ((res = extract_header(avctx, avpkt)) < 0) return res; - if ((res = ff_reget_buffer(avctx, s->frame)) < 0) + + if ((res = ff_get_buffer(avctx, frame, 0)) < 0) return res; + s->frame = frame; + buf += bytestream2_tell(gb); + buf_size -= bytestream2_tell(gb); desc = av_pix_fmt_desc_get(avctx->pix_fmt); if (!s->init && avctx->bits_per_coded_sample <= 8 && avctx->pix_fmt == AV_PIX_FMT_PAL8) { - if ((res = cmap_read_palette(avctx, (uint32_t *)s->frame->data[1])) < 0) + if ((res = cmap_read_palette(avctx, (uint32_t *)frame->data[1])) < 0) return res; } else if (!s->init && avctx->bits_per_coded_sample <= 8 && avctx->pix_fmt == AV_PIX_FMT_RGB32) { @@ -697,22 +804,32 @@ static int decode_frame(AVCodecContext *avctx, } s->init = 1; + if (s->compression <= 0xff && avctx->codec_tag == MKTAG('A', 'N', 'I', 'M') && + avctx->pix_fmt == AV_PIX_FMT_PAL8) + memcpy(s->pal[0], s->frame->data[1], 256 * 4); + + if (s->compression > 0xff && s->first) { + memcpy(s->video[1], s->video[0], s->video_size); + memcpy(s->pal[1], s->pal[0], 256 * 4); + s->first = 0; + } + switch (s->compression) { - case 0: + case 0x0: if (avctx->codec_tag == MKTAG('A', 'C', 'B', 'M')) { if (avctx->pix_fmt == AV_PIX_FMT_PAL8 || avctx->pix_fmt == AV_PIX_FMT_GRAY8) { - memset(s->frame->data[0], 0, avctx->height * s->frame->linesize[0]); + memset(frame->data[0], 0, avctx->height * frame->linesize[0]); for (plane = 0; plane < s->bpp; plane++) { for (y = 0; y < avctx->height && buf < buf_end; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; decodeplane8(row, buf, FFMIN(s->planesize, buf_end - buf), plane); buf += s->planesize; } } } else if (s->ham) { // HAM to AV_PIX_FMT_BGR32 - memset(s->frame->data[0], 0, avctx->height * s->frame->linesize[0]); + memset(frame->data[0], 0, avctx->height * frame->linesize[0]); for (y = 0; y < avctx->height; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memset(s->ham_buf, 0, s->planesize * 8); for (plane = 0; plane < s->bpp; plane++) { const uint8_t * start = buf + (plane * avctx->height + y) * s->planesize; @@ -728,7 +845,7 @@ static int decode_frame(AVCodecContext *avctx, int raw_width = avctx->width * (av_get_bits_per_pixel(desc) >> 3); int x; for (y = 0; y < avctx->height && buf < buf_end; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memcpy(row, buf, FFMIN(raw_width, buf_end - buf)); buf += raw_width; if (avctx->pix_fmt == AV_PIX_FMT_BGR32) { @@ -736,10 +853,13 @@ static int decode_frame(AVCodecContext *avctx, row[4 * x + 3] = row[4 * x + 3] & 0xF0 | (row[4 * x + 3] >> 4); } } - } else if (avctx->codec_tag == MKTAG('I', 'L', 'B', 'M')) { // interleaved + } else if (avctx->codec_tag == MKTAG('I', 'L', 'B', 'M') || // interleaved + avctx->codec_tag == MKTAG('A', 'N', 'I', 'M')) { if (avctx->pix_fmt == AV_PIX_FMT_PAL8 || avctx->pix_fmt == AV_PIX_FMT_GRAY8) { + if (avctx->codec_tag == MKTAG('A', 'N', 'I', 'M')) + memcpy(s->video[0], buf, FFMIN(buf_end - buf, s->video_size)); for (y = 0; y < avctx->height; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memset(row, 0, avctx->width); for (plane = 0; plane < s->bpp && buf < buf_end; plane++) { decodeplane8(row, buf, FFMIN(s->planesize, buf_end - buf), plane); @@ -748,7 +868,7 @@ static int decode_frame(AVCodecContext *avctx, } } else if (s->ham) { // HAM to AV_PIX_FMT_BGR32 for (y = 0; y < avctx->height; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memset(s->ham_buf, 0, s->planesize * 8); for (plane = 0; plane < s->bpp && buf < buf_end; plane++) { decodeplane8(s->ham_buf, buf, FFMIN(s->planesize, buf_end - buf), plane); @@ -758,7 +878,7 @@ static int decode_frame(AVCodecContext *avctx, } } else { // AV_PIX_FMT_BGR32 for (y = 0; y < avctx->height; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memset(row, 0, avctx->width << 2); for (plane = 0; plane < s->bpp && buf < buf_end; plane++) { decodeplane32((uint32_t *)row, buf, @@ -770,13 +890,13 @@ static int decode_frame(AVCodecContext *avctx, } else if (avctx->codec_tag == MKTAG('P', 'B', 'M', ' ')) { // IFF-PBM if (avctx->pix_fmt == AV_PIX_FMT_PAL8 || avctx->pix_fmt == AV_PIX_FMT_GRAY8) { for (y = 0; y < avctx->height && buf_end > buf; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memcpy(row, buf, FFMIN(avctx->width, buf_end - buf)); buf += avctx->width + (avctx->width % 2); // padding if odd } } else if (s->ham) { // IFF-PBM: HAM to AV_PIX_FMT_BGR32 for (y = 0; y < avctx->height && buf_end > buf; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memcpy(s->ham_buf, buf, FFMIN(avctx->width, buf_end - buf)); buf += avctx->width + (avctx->width & 1); // padding if odd decode_ham_plane32((uint32_t *)row, s->ham_buf, s->ham_palbuf, s->planesize); @@ -785,43 +905,55 @@ static int decode_frame(AVCodecContext *avctx, return unsupported(avctx); } break; - case 1: - if (avctx->codec_tag == MKTAG('I', 'L', 'B', 'M')) { // interleaved + case 0x1: + if (avctx->codec_tag == MKTAG('I', 'L', 'B', 'M') || // interleaved + avctx->codec_tag == MKTAG('A', 'N', 'I', 'M')) { if (avctx->pix_fmt == AV_PIX_FMT_PAL8 || avctx->pix_fmt == AV_PIX_FMT_GRAY8) { + uint8_t *video = s->video[0]; + for (y = 0; y < avctx->height; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memset(row, 0, avctx->width); for (plane = 0; plane < s->bpp; plane++) { - buf += decode_byterun(s->planebuf, s->planesize, buf, buf_end); + buf += decode_byterun(s->planebuf, s->planesize, gb); + if (avctx->codec_tag == MKTAG('A', 'N', 'I', 'M')) { + memcpy(video, s->planebuf, s->planesize); + video += s->planesize; + } decodeplane8(row, s->planebuf, s->planesize, plane); } } } else if (avctx->bits_per_coded_sample <= 8) { //8-bit (+ mask) to AV_PIX_FMT_BGR32 for (y = 0; y < avctx->height; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memset(s->mask_buf, 0, avctx->width * sizeof(uint32_t)); for (plane = 0; plane < s->bpp; plane++) { - buf += decode_byterun(s->planebuf, s->planesize, buf, buf_end); + buf += decode_byterun(s->planebuf, s->planesize, gb); decodeplane32(s->mask_buf, s->planebuf, s->planesize, plane); } lookup_pal_indicies((uint32_t *)row, s->mask_buf, s->mask_palbuf, avctx->width); } } else if (s->ham) { // HAM to AV_PIX_FMT_BGR32 + uint8_t *video = s->video[0]; for (y = 0; y < avctx->height; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memset(s->ham_buf, 0, s->planesize * 8); for (plane = 0; plane < s->bpp; plane++) { - buf += decode_byterun(s->planebuf, s->planesize, buf, buf_end); + buf += decode_byterun(s->planebuf, s->planesize, gb); + if (avctx->codec_tag == MKTAG('A', 'N', 'I', 'M')) { + memcpy(video, s->planebuf, s->planesize); + video += s->planesize; + } decodeplane8(s->ham_buf, s->planebuf, s->planesize, plane); } decode_ham_plane32((uint32_t *)row, s->ham_buf, s->ham_palbuf, s->planesize); } } else { // AV_PIX_FMT_BGR32 for (y = 0; y < avctx->height; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memset(row, 0, avctx->width << 2); for (plane = 0; plane < s->bpp; plane++) { - buf += decode_byterun(s->planebuf, s->planesize, buf, buf_end); + buf += decode_byterun(s->planebuf, s->planesize, gb); decodeplane32((uint32_t *)row, s->planebuf, s->planesize, plane); } } @@ -829,48 +961,106 @@ static int decode_frame(AVCodecContext *avctx, } else if (avctx->codec_tag == MKTAG('P', 'B', 'M', ' ')) { // IFF-PBM if (avctx->pix_fmt == AV_PIX_FMT_PAL8 || avctx->pix_fmt == AV_PIX_FMT_GRAY8) { for (y = 0; y < avctx->height; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; - buf += decode_byterun(row, avctx->width, buf, buf_end); + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; + buf += decode_byterun(row, avctx->width, gb); } } else if (s->ham) { // IFF-PBM: HAM to AV_PIX_FMT_BGR32 for (y = 0; y < avctx->height; y++) { - uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; - buf += decode_byterun(s->ham_buf, avctx->width, buf, buf_end); + uint8_t *row = &frame->data[0][y * frame->linesize[0]]; + buf += decode_byterun(s->ham_buf, avctx->width, gb); decode_ham_plane32((uint32_t *)row, s->ham_buf, s->ham_palbuf, s->planesize); } } else return unsupported(avctx); } else if (avctx->codec_tag == MKTAG('D', 'E', 'E', 'P')) { // IFF-DEEP if (av_get_bits_per_pixel(desc) == 32) - decode_deep_rle32(s->frame->data[0], buf, buf_size, avctx->width, avctx->height, s->frame->linesize[0]); + decode_deep_rle32(frame->data[0], buf, buf_size, avctx->width, avctx->height, frame->linesize[0]); else return unsupported(avctx); } break; - case 4: - bytestream2_init(&gb, buf, buf_size); + case 0x4: if (avctx->codec_tag == MKTAG('R', 'G', 'B', '8') && avctx->pix_fmt == AV_PIX_FMT_RGB32) - decode_rgb8(&gb, s->frame->data[0], avctx->width, avctx->height, s->frame->linesize[0]); + decode_rgb8(gb, frame->data[0], avctx->width, avctx->height, frame->linesize[0]); else if (avctx->codec_tag == MKTAG('R', 'G', 'B', 'N') && avctx->pix_fmt == AV_PIX_FMT_RGB444) - decode_rgbn(&gb, s->frame->data[0], avctx->width, avctx->height, s->frame->linesize[0]); + decode_rgbn(gb, frame->data[0], avctx->width, avctx->height, frame->linesize[0]); else return unsupported(avctx); break; - case 5: + case 0x5: if (avctx->codec_tag == MKTAG('D', 'E', 'E', 'P')) { if (av_get_bits_per_pixel(desc) == 32) - decode_deep_tvdc32(s->frame->data[0], buf, buf_size, avctx->width, avctx->height, s->frame->linesize[0], s->tvdc); + decode_deep_tvdc32(frame->data[0], buf, buf_size, avctx->width, avctx->height, frame->linesize[0], s->tvdc); else return unsupported(avctx); } else return unsupported(avctx); break; + case 0x500: + case 0x501: + decode_byte_vertical_delta(s->video[0], buf, buf_end, avctx->width, avctx->height, s->bpp); + + 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); + break; default: return unsupported(avctx); } - if ((res = av_frame_ref(data, s->frame)) < 0) - return res; + if (s->compression > 0xff) { + 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; diff --git a/libavformat/iff.c b/libavformat/iff.c index 2889083..2861785 100644 --- a/libavformat/iff.c +++ b/libavformat/iff.c @@ -60,6 +60,8 @@ #define ID_RGBN MKTAG('R','G','B','N') #define ID_DSD MKTAG('D','S','D',' ') #define ID_ANIM MKTAG('A','N','I','M') +#define ID_ANHD MKTAG('A','N','H','D') +#define ID_DLTA MKTAG('D','L','T','A') #define ID_FORM MKTAG('F','O','R','M') #define ID_FRM8 MKTAG('F','R','M','8') @@ -113,6 +115,7 @@ typedef struct IffDemuxContext { unsigned transparency; ///< transparency color index in palette unsigned masking; ///< masking method used uint8_t tvdc[32]; ///< TVDC lookup table + int64_t pts; } IffDemuxContext; /* Metadata string read */ @@ -367,8 +370,7 @@ static int iff_read_header(AVFormatContext *s) // codec_tag used by ByteRun1 decoder to distinguish progressive (PBM) and interlaced (ILBM) content st->codec->codec_tag = avio_rl32(pb); if (st->codec->codec_tag == ID_ANIM) { - avio_skip(pb, 8); - st->codec->codec_tag = avio_rl32(pb); + avio_skip(pb, 12); } iff->bitmap_compression = -1; iff->svx8_compression = -1; @@ -484,6 +486,11 @@ static int iff_read_header(AVFormatContext *s) } break; + case ID_ANHD: + if (data_size != 40) + return AVERROR_INVALIDDATA; + break; + case ID_DPEL: if (data_size < 4 || (data_size & 3)) return AVERROR_INVALIDDATA; @@ -626,7 +633,10 @@ static int iff_read_header(AVFormatContext *s) avio_skip(pb, data_size - (avio_tell(pb) - orig_pos) + (data_size & 1)); } - avio_seek(pb, iff->body_pos, SEEK_SET); + if (st->codec->codec_tag == ID_ANIM) + avio_seek(pb, 12, SEEK_SET); + else + avio_seek(pb, iff->body_pos, SEEK_SET); switch(st->codec->codec_type) { case AVMEDIA_TYPE_AUDIO: @@ -671,6 +681,7 @@ static int iff_read_header(AVFormatContext *s) break; case AVMEDIA_TYPE_VIDEO: + avpriv_set_pts_info(st, 32, 1, 60); iff->bpp = st->codec->bits_per_coded_sample; if ((screenmode & 0x800 /* Hold And Modify */) && iff->bpp <= 8) { iff->ham = iff->bpp > 6 ? 6 : 4; @@ -714,8 +725,12 @@ static int iff_read_packet(AVFormatContext *s, int ret; int64_t pos = avio_tell(pb); - if (pos >= iff->body_end) + if (st->codec->codec_tag == ID_ANIM) { + if (avio_feof(pb)) + return AVERROR_EOF; + } else if (pos >= iff->body_end) { return AVERROR_EOF; + } if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { if (st->codec->codec_tag == ID_DSD || st->codec->codec_tag == ID_MAUD) { @@ -725,22 +740,30 @@ static int iff_read_packet(AVFormatContext *s, return AVERROR_INVALIDDATA; ret = av_get_packet(pb, pkt, iff->body_size); } - } else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { - uint8_t *buf; + } else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && + st->codec->codec_tag == ID_ANIM) { + uint64_t data_size, orig_pos; + uint32_t chunk_id = 0; - if (iff->body_size > INT_MAX - 2) - return AVERROR_INVALIDDATA; - if (av_new_packet(pkt, iff->body_size + 2) < 0) { - return AVERROR(ENOMEM); - } + while (!avio_feof(pb)) { + if (avio_feof(pb)) + return AVERROR_EOF; + + chunk_id = avio_rl32(pb); + data_size = avio_rb32(pb); + orig_pos = avio_tell(pb); - buf = pkt->data; - bytestream_put_be16(&buf, 2); - ret = avio_read(pb, buf, iff->body_size); - if (ret<0) { - av_packet_unref(pkt); - } else if (ret < iff->body_size) - av_shrink_packet(pkt, ret + 2); + if (chunk_id == ID_FORM) + break; + else + avio_skip(pb, data_size); + } + ret = av_get_packet(pb, pkt, data_size); + pos = orig_pos; + pkt->duration = 3; + } else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && + st->codec->codec_tag != ID_ANIM) { + ret = av_get_packet(pb, pkt, iff->body_size); } else { av_assert0(0); } @@ -750,6 +773,7 @@ static int iff_read_packet(AVFormatContext *s, if (ret < 0) return ret; pkt->stream_index = 0; + pkt->pos = pos; return ret; } diff --git a/tests/ref/fate/iff-byterun1 b/tests/ref/fate/iff-byterun1 index 6f80c72..6594087 100644 --- a/tests/ref/fate/iff-byterun1 +++ b/tests/ref/fate/iff-byterun1 @@ -1,2 +1,2 @@ -#tb 0: 1/90000 -0, 0, 0, 0, 230400, 0x35e51c62 +#tb 0: 1/60 +0, 0, 0, 1, 230400, 0x35e51c62 diff --git a/tests/ref/fate/iff-ilbm b/tests/ref/fate/iff-ilbm index a801aff..14d57e6 100644 --- a/tests/ref/fate/iff-ilbm +++ b/tests/ref/fate/iff-ilbm @@ -1,2 +1,2 @@ -#tb 0: 1/90000 -0, 0, 0, 0, 230400, 0x0929e342 +#tb 0: 1/60 +0, 0, 0, 1, 230400, 0x0929e342 -- 1.9.1
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel