summaryrefslogtreecommitdiff
path: root/libavformat/iff.c
diff options
context:
space:
mode:
authorSebastian Vater <cdgs.basty@googlemail.com>2011-04-20 13:56:56 +0200
committerMichael Niedermayer <michaelni@gmx.at>2011-04-24 12:45:19 +0200
commit183132872a1d8bc8a32e7fd8f994fa2f1b2d6bfc (patch)
tree71158e36dd5936690b9a17a431ef89551fdc2fe4 /libavformat/iff.c
parentc2a8f125855aef72efcde8a06dd73a5fbe5dcf25 (diff)
HAM6/HAM8 support for IFF demuxer/decoder
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavformat/iff.c')
-rw-r--r--libavformat/iff.c78
1 files changed, 71 insertions, 7 deletions
diff --git a/libavformat/iff.c b/libavformat/iff.c
index 24942122ad..da4e858501 100644
--- a/libavformat/iff.c
+++ b/libavformat/iff.c
@@ -29,6 +29,7 @@
* http://wiki.multimedia.cx/index.php?title=IFF
*/
+#include "libavcodec/bytestream.h"
#include "libavutil/intreadwrite.h"
#include "avformat.h"
@@ -40,6 +41,7 @@
#define ID_PBM MKTAG('P','B','M',' ')
#define ID_ILBM MKTAG('I','L','B','M')
#define ID_BMHD MKTAG('B','M','H','D')
+#define ID_CAMG MKTAG('C','A','M','G')
#define ID_CMAP MKTAG('C','M','A','P')
#define ID_FORM MKTAG('F','O','R','M')
@@ -60,6 +62,16 @@
#define PACKET_SIZE 1024
+/**
+ * This number of bytes if added at the beginning of each AVPacket
+ * which contain additional information about video properties
+ * which has to be shared between demuxer and decoder.
+ * This number may change between frames, e.g. the demuxer might
+ * set it to smallest possible size of 2 to indicate that there's
+ * no extradata changing in this frame.
+ */
+#define IFF_EXTRA_VIDEO_SIZE 9
+
typedef enum {
COMP_NONE,
COMP_FIB,
@@ -76,6 +88,12 @@ typedef struct {
uint32_t body_size;
uint32_t sent_bytes;
uint32_t audio_frame_count;
+ unsigned compression; ///< delta compression method used
+ unsigned bpp; ///< bits per plane to decode (differs from bits_per_coded_sample if HAM)
+ unsigned ham; ///< 0 if non-HAM or number of hold bits (6 for bpp > 6, 4 otherwise)
+ unsigned flags; ///< 1 for EHB, 0 is no extra half darkening
+ unsigned transparency; ///< transparency color index in palette
+ unsigned masking; ///< masking method used
} IffDemuxContext;
@@ -126,8 +144,12 @@ static int iff_read_header(AVFormatContext *s,
IffDemuxContext *iff = s->priv_data;
AVIOContext *pb = s->pb;
AVStream *st;
+ uint8_t *buf;
uint32_t chunk_id, data_size;
int compression = -1;
+ uint32_t screenmode = 0;
+ unsigned transparency = 0;
+ unsigned masking = 0; // no mask
st = av_new_stream(s, 0);
if (!st)
@@ -171,12 +193,18 @@ static int iff_read_header(AVFormatContext *s,
st->codec->channels = (avio_rb32(pb) < 6) ? 1 : 2;
break;
+ case ID_CAMG:
+ if (data_size < 4)
+ return AVERROR_INVALIDDATA;
+ screenmode = avio_rb32(pb);
+ break;
+
case ID_CMAP:
- st->codec->extradata_size = data_size;
- st->codec->extradata = av_malloc(data_size);
+ st->codec->extradata_size = data_size + IFF_EXTRA_VIDEO_SIZE;
+ st->codec->extradata = av_malloc(data_size + IFF_EXTRA_VIDEO_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
if (!st->codec->extradata)
return AVERROR(ENOMEM);
- if (avio_read(pb, st->codec->extradata, data_size) < 0)
+ if (avio_read(pb, st->codec->extradata + IFF_EXTRA_VIDEO_SIZE, data_size) < 0)
return AVERROR(EIO);
break;
@@ -188,12 +216,15 @@ static int iff_read_header(AVFormatContext *s,
st->codec->height = avio_rb16(pb);
avio_skip(pb, 4); // x, y offset
st->codec->bits_per_coded_sample = avio_r8(pb);
- if (data_size >= 11) {
- avio_skip(pb, 1); // masking
+ if (data_size >= 10)
+ masking = avio_r8(pb);
+ if (data_size >= 11)
compression = avio_r8(pb);
+ if (data_size >= 14) {
+ avio_skip(pb, 1); // padding
+ transparency = avio_rb16(pb);
}
if (data_size >= 16) {
- avio_skip(pb, 3); // paddding, transparent
st->sample_aspect_ratio.num = avio_r8(pb);
st->sample_aspect_ratio.den = avio_r8(pb);
}
@@ -253,6 +284,31 @@ static int iff_read_header(AVFormatContext *s,
break;
case AVMEDIA_TYPE_VIDEO:
+ iff->compression = compression;
+ iff->bpp = st->codec->bits_per_coded_sample;
+ if ((screenmode & 0x800 /* Hold And Modify */) && iff->bpp <= 8) {
+ iff->ham = iff->bpp > 6 ? 6 : 4;
+ st->codec->bits_per_coded_sample = 24;
+ }
+ iff->flags = (screenmode & 0x80 /* Extra HalfBrite */) && iff->bpp <= 8;
+ iff->masking = masking;
+ iff->transparency = transparency;
+
+ if (!st->codec->extradata) {
+ st->codec->extradata_size = IFF_EXTRA_VIDEO_SIZE;
+ st->codec->extradata = av_malloc(IFF_EXTRA_VIDEO_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!st->codec->extradata)
+ return AVERROR(ENOMEM);
+ }
+ buf = st->codec->extradata;
+ bytestream_put_be16(&buf, IFF_EXTRA_VIDEO_SIZE);
+ bytestream_put_byte(&buf, iff->compression);
+ bytestream_put_byte(&buf, iff->bpp);
+ bytestream_put_byte(&buf, iff->ham);
+ bytestream_put_byte(&buf, iff->flags);
+ bytestream_put_be16(&buf, iff->transparency);
+ bytestream_put_byte(&buf, iff->masking);
+
switch (compression) {
case BITMAP_RAW:
st->codec->codec_id = CODEC_ID_IFF_ILBM;
@@ -293,7 +349,15 @@ static int iff_read_packet(AVFormatContext *s,
}
interleave_stereo(sample_buffer, pkt->data, PACKET_SIZE);
} else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
- ret = av_get_packet(pb, pkt, iff->body_size);
+ uint8_t *buf;
+
+ if (av_new_packet(pkt, iff->body_size + 2) < 0) {
+ return AVERROR(ENOMEM);
+ }
+
+ buf = pkt->data;
+ bytestream_put_be16(&buf, 2);
+ ret = avio_read(pb, buf, iff->body_size);
} else {
ret = av_get_packet(pb, pkt, PACKET_SIZE);
}