summaryrefslogtreecommitdiff
authorMike Melanson <mike@multimedia.cx>2004-03-13 17:30:37 (GMT)
committer Mike Melanson <mike@multimedia.cx>2004-03-13 17:30:37 (GMT)
commit6a91ec51fd08784bd836449a998def1dbe54772e (patch)
treeb232222108af6057d43484ac4fb434e5307c2895
parent38088adf638f42c7c35a17c181b4cc60d55dcb9a (diff)
downloadffmpeg-6a91ec51fd08784bd836449a998def1dbe54772e.zip
ffmpeg-6a91ec51fd08784bd836449a998def1dbe54772e.tar.gz
ffmpeg-6a91ec51fd08784bd836449a998def1dbe54772e.tar.bz2
added SGI image format, encoding and decoding, courtesy of Todd Kirby
<doubleshot@pacbell.net> Originally committed as revision 2876 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat
-rw-r--r--CREDITS1
-rw-r--r--doc/ffmpeg-doc.texi1
-rw-r--r--libavformat/Makefile2
-rw-r--r--libavformat/allformats.c1
-rw-r--r--libavformat/avformat.h1
-rw-r--r--libavformat/sgi.c475
6 files changed, 480 insertions, 1 deletions
diff --git a/CREDITS b/CREDITS
index ce76154..f0dd26a 100644
--- a/CREDITS
+++ b/CREDITS
@@ -15,6 +15,7 @@ Wolfgang Hesseler
Falk Hueffner
Zdenek Kabelac
Robin Kay
+Todd Kirby
Nick Kurshev
Mike Melanson
Michael Niedermayer
diff --git a/doc/ffmpeg-doc.texi b/doc/ffmpeg-doc.texi
index 849b93a..e205904 100644
--- a/doc/ffmpeg-doc.texi
+++ b/doc/ffmpeg-doc.texi
@@ -678,6 +678,7 @@ following image formats are supported:
@item .Y.U.V @tab X @tab X @tab One raw file per component
@item Animated GIF @tab X @tab X @tab Only uncompressed GIFs are generated
@item PNG @tab X @tab X @tab 2 bit and 4 bit/pixel not supported yet
+@item SGI @tab X @tab X @tab SGI RGB image format
@end multitable
@code{X} means that the encoding (resp. decoding) is supported.
diff --git a/libavformat/Makefile b/libavformat/Makefile
index 0b8161b..23aecba 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -34,7 +34,7 @@ OBJS+= amr.o
endif
# image formats
-OBJS+= pnm.o yuv.o png.o jpeg.o gifdec.o
+OBJS+= pnm.o yuv.o png.o jpeg.o gifdec.o sgi.o
# file I/O
OBJS+= avio.o aviobuf.o file.o
OBJS+= framehook.o
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index b0b0e64..9feaa98 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -112,6 +112,7 @@ void av_register_all(void)
#endif
av_register_image_format(&jpeg_image_format);
av_register_image_format(&gif_image_format);
+ av_register_image_format(&sgi_image_format);
#endif //CONFIG_ENCODERS
/* file protocols */
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 5d87ac7..5da4d9c 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -366,6 +366,7 @@ extern AVImageFormat png_image_format;
#endif
extern AVImageFormat jpeg_image_format;
extern AVImageFormat gif_image_format;
+extern AVImageFormat sgi_image_format;
/* XXX: use automatic init with either ELF sections or C file parser */
/* modules */
diff --git a/libavformat/sgi.c b/libavformat/sgi.c
new file mode 100644
index 0000000..11b6ab5
--- a/dev/null
+++ b/libavformat/sgi.c
@@ -0,0 +1,475 @@
+/*
+ * SGI image format
+ * Todd Kirby <doubleshot@pacbell.net>
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "avformat.h"
+#include "avio.h"
+
+/* #define DEBUG */
+
+#define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1])
+
+#define BE_32(x) ((((uint8_t*)(x))[0] << 24) | \
+ (((uint8_t*)(x))[1] << 16) | \
+ (((uint8_t*)(x))[2] << 8) | \
+ ((uint8_t*)(x))[3])
+
+/* sgi image file signature */
+#define SGI_MAGIC 474
+
+#define SGI_HEADER_SIZE 512
+
+#define SGI_GRAYSCALE 1
+#define SGI_RGB 3
+#define SGI_RGBA 4
+
+#define SGI_SINGLE_CHAN 2
+#define SGI_MULTI_CHAN 3
+
+typedef struct SGIInfo{
+ short magic;
+ char rle;
+ char bytes_per_channel;
+ unsigned short dimension;
+ unsigned short xsize;
+ unsigned short ysize;
+ unsigned short zsize;
+} SGIInfo;
+
+
+static int sgi_probe(AVProbeData *pd)
+{
+ /* test for sgi magic */
+ if (pd->buf_size >= 2 && BE_16(&pd->buf[0]) == SGI_MAGIC) {
+ return AVPROBE_SCORE_MAX;
+ } else {
+ return 0;
+ }
+}
+
+/* read sgi header fields */
+static void read_sgi_header(ByteIOContext *f, SGIInfo *info)
+{
+ info->magic = (unsigned short) get_be16(f);
+ info->rle = get_byte(f);
+ info->bytes_per_channel = get_byte(f);
+ info->dimension = (unsigned short)get_be16(f);
+ info->xsize = (unsigned short) get_be16(f);
+ info->ysize = (unsigned short) get_be16(f);
+ info->zsize = (unsigned short) get_be16(f);
+
+#ifdef DEBUG
+ printf("sgi header fields:\n");
+ printf(" magic: %d\n", info->magic);
+ printf(" rle: %d\n", info->rle);
+ printf(" bpc: %d\n", info->bytes_per_channel);
+ printf(" dim: %d\n", info->dimension);
+ printf(" xsize: %d\n", info->xsize);
+ printf(" ysize: %d\n", info->ysize);
+ printf(" zsize: %d\n", info->zsize);
+#endif
+
+ return;
+}
+
+
+/* read an uncompressed sgi image */
+static int read_uncompressed_sgi(const SGIInfo *si,
+ AVPicture *pict, ByteIOContext *f)
+{
+ int x, y, z, chan_offset, ret = 0;
+ uint8_t *dest_row, *tmp_row = NULL;
+
+ tmp_row = av_malloc(si->xsize);
+
+ /* skip header */
+ url_fseek(f, SGI_HEADER_SIZE, SEEK_SET);
+
+ pict->linesize[0] = si->xsize;
+
+ for (z = 0; z < si->zsize; z++) {
+
+#ifndef WORDS_BIGENDIAN
+ /* rgba -> bgra for rgba32 on little endian cpus */
+ if (si->zsize == 4 && z != 3)
+ chan_offset = 2 - z;
+ else
+#endif
+ chan_offset = z;
+
+ for (y = si->ysize - 1; y >= 0; y--) {
+ dest_row = pict->data[0] + (y * si->xsize * si->zsize);
+
+ if (!get_buffer(f, tmp_row, si->xsize)) {
+ ret = -1;
+ goto cleanup;
+ }
+ for (x = 0; x < si->xsize; x++) {
+ dest_row[chan_offset] = tmp_row[x];
+ dest_row += si->zsize;
+ }
+ }
+ }
+
+cleanup:
+ av_free(tmp_row);
+ return ret;
+}
+
+
+/* expand an rle row into a channel */
+static void expand_rle_row(unsigned char *optr, unsigned char *iptr,
+ int chan_offset, int pixelstride)
+{
+ unsigned char pixel, count;
+
+#ifndef WORDS_BIGENDIAN
+ /* rgba -> bgra for rgba32 on little endian cpus */
+ if (pixelstride == 4 && chan_offset != 3) {
+ chan_offset = 2 - chan_offset;
+ }
+#endif
+
+ optr += chan_offset;
+
+ while (1) {
+ pixel = *iptr++;
+
+ if (!(count = (pixel & 0x7f))) {
+ return;
+ }
+ if (pixel & 0x80) {
+ while (count--) {
+ *optr = *iptr;
+ optr += pixelstride;
+ iptr++;
+ }
+ } else {
+ pixel = *iptr++;
+
+ while (count--) {
+ *optr = pixel;
+ optr += pixelstride;
+ }
+ }
+ }
+}
+
+
+/* read a run length encoded sgi image */
+static int read_rle_sgi(const SGIInfo *sgi_info,
+ AVPicture *pict, ByteIOContext *f)
+{
+ uint8_t *dest_row, *rle_data = NULL;
+ unsigned long *start_table, *length_table;
+ int y, z, xsize, ysize, zsize, tablen;
+ long start_offset, run_length;
+ int ret = 0;
+
+ xsize = sgi_info->xsize;
+ ysize = sgi_info->ysize;
+ zsize = sgi_info->zsize;
+
+ rle_data = av_malloc(xsize);
+
+ /* skip header */
+ url_fseek(f, SGI_HEADER_SIZE, SEEK_SET);
+
+ /* size of rle offset and length tables */
+ tablen = ysize * zsize * sizeof(long);
+
+ start_table = (unsigned long *)av_malloc(tablen);
+ length_table = (unsigned long *)av_malloc(tablen);
+
+ if (!get_buffer(f, (uint8_t *)start_table, tablen)) {
+ ret = -1;
+ goto fail;
+ }
+
+ if (!get_buffer(f, (uint8_t *)length_table, tablen)) {
+ ret = -1;
+ goto fail;
+ }
+
+ for (z = 0; z < zsize; z++) {
+ for (y = 0; y < ysize; y++) {
+ dest_row = pict->data[0] + (ysize - 1 - y) * (xsize * zsize);
+
+ start_offset = BE_32(&start_table[y + z * ysize]);
+ run_length = BE_32(&length_table[y + z * ysize]);
+
+ /* don't seek if already in the correct spot */
+ if (url_ftell(f) != start_offset) {
+ url_fseek(f, start_offset, SEEK_SET);
+ }
+
+ get_buffer(f, rle_data, run_length);
+
+ expand_rle_row(dest_row, rle_data, z, zsize);
+ }
+ }
+
+fail:
+ av_free(start_table);
+ av_free(length_table);
+ av_free(rle_data);
+
+ return ret;
+}
+
+
+static int sgi_read(ByteIOContext *f,
+ int (*alloc_cb)(void *opaque, AVImageInfo *info), void *opaque)
+{
+ SGIInfo sgi_info, *s = &sgi_info;
+ AVImageInfo info1, *info = &info1;
+ int ret;
+
+ read_sgi_header(f, s);
+
+ if (s->bytes_per_channel != 1) {
+ return AVERROR_INVALIDDATA;
+ }
+
+ /* check for supported image dimensions */
+ if (s->dimension != 2 && s->dimension != 3) {
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (s->zsize == SGI_GRAYSCALE) {
+ info->pix_fmt = PIX_FMT_GRAY8;
+ } else if (s->zsize == SGI_RGB) {
+ info->pix_fmt = PIX_FMT_RGB24;
+ } else if (s->zsize == SGI_RGBA) {
+ info->pix_fmt = PIX_FMT_RGBA32;
+ } else {
+ return AVERROR_INVALIDDATA;
+ }
+
+ info->width = s->xsize;
+ info->height = s->ysize;
+
+ ret = alloc_cb(opaque, info);
+ if (ret)
+ return ret;
+
+ if (s->rle) {
+ return read_rle_sgi(s, &info->pict, f);
+ } else {
+ return read_uncompressed_sgi(s, &info->pict, f);
+ }
+
+ return 0; /* not reached */
+}
+
+#ifdef CONFIG_ENCODERS
+static void write_sgi_header(ByteIOContext *f, const SGIInfo *info)
+{
+ int i;
+
+ put_be16(f, SGI_MAGIC);
+ put_byte(f, info->rle);
+ put_byte(f, info->bytes_per_channel);
+ put_be16(f, info->dimension);
+ put_be16(f, info->xsize);
+ put_be16(f, info->ysize);
+ put_be16(f, info->zsize);
+
+ /* The rest are constant in this implementation */
+ put_be32(f, 0L); /* pixmin */
+ put_be32(f, 255L); /* pixmax */
+ put_be32(f, 0L); /* dummy */
+
+ /* name */
+ for (i = 0; i < 80; i++) {
+ put_byte(f, 0);
+ }
+
+ put_be32(f, 0L); /* colormap */
+
+ /* The rest of the 512 byte header is unused. */
+ for (i = 0; i < 404; i++) {
+ put_byte(f, 0);
+ }
+}
+
+
+static int rle_row(ByteIOContext *f, char *row, int stride, int rowsize)
+{
+ int length, count, i, x;
+ char *start, repeat = 0;
+
+ for (x = rowsize, length = 0; x > 0;) {
+ start = row;
+ row += (2 * stride);
+ x -= 2;
+
+ while (x > 0 && (row[-2 * stride] != row[-1 * stride] ||
+ row[-1 * stride] != row[0])) {
+ row += stride;
+ x--;
+ };
+
+ row -= (2 * stride);
+ x += 2;
+
+ count = (row - start) / stride;
+ while (count > 0) {
+ i = count > 126 ? 126 : count;
+ count -= i;
+
+ put_byte(f, 0x80 | i);
+ length++;
+
+ while (i > 0) {
+ put_byte(f, *start);
+ start += stride;
+ i--;
+ length++;
+ };
+ };
+
+ if (x <= 0) {
+ break;
+ }
+
+ start = row;
+ repeat = row[0];
+
+ row += stride;
+ x--;
+
+ while (x > 0 && *row == repeat) {
+ row += stride;
+ x--;
+ };
+
+ count = (row - start) / stride;
+ while (count > 0) {
+ i = count > 126 ? 126 : count;
+ count -= i;
+
+ put_byte(f, i);
+ length++;
+
+ put_byte(f, repeat);
+ length++;
+ };
+ };
+
+ length++;
+
+ put_byte(f, 0);
+ return (length);
+}
+
+
+static int sgi_write(ByteIOContext *pb, AVImageInfo *info)
+{
+ SGIInfo sgi_info, *si = &sgi_info;
+ long *offsettab, *lengthtab;
+ int i, y, z;
+ int tablesize, chan_offset;
+ uint8_t *srcrow;
+
+ si->xsize = info->width;
+ si->ysize = info->height;
+ si->rle = 1;
+ si->bytes_per_channel = 1;
+
+ switch(info->pix_fmt) {
+ case PIX_FMT_GRAY8:
+ si->dimension = SGI_SINGLE_CHAN;
+ si->zsize = SGI_GRAYSCALE;
+ break;
+ case PIX_FMT_RGB24:
+ si->dimension = SGI_MULTI_CHAN;
+ si->zsize = SGI_RGB;
+ break;
+ case PIX_FMT_RGBA32:
+ si->dimension = SGI_MULTI_CHAN;
+ si->zsize = SGI_RGBA;
+ break;
+ default:
+ return AVERROR_INVALIDDATA;
+ }
+
+ write_sgi_header(pb, si);
+
+ tablesize = si->zsize * si->ysize * sizeof(long);
+
+ /* skip rle offset and length tables, write them at the end. */
+ url_fseek(pb, tablesize * 2, SEEK_CUR);
+ put_flush_packet(pb);
+
+ lengthtab = av_malloc(tablesize);
+ offsettab = av_malloc(tablesize);
+
+ for (z = 0; z < si->zsize; z++) {
+
+#ifndef WORDS_BIGENDIAN
+ /* rgba -> bgra for rgba32 on little endian cpus */
+ if (si->zsize == 4 && z != 3)
+ chan_offset = 2 - z;
+ else
+#endif
+ chan_offset = z;
+
+ srcrow = info->pict.data[0] + chan_offset;
+
+ for (y = si->ysize -1; y >= 0; y--) {
+ offsettab[(z * si->ysize) + y] = url_ftell(pb);
+ lengthtab[(z * si->ysize) + y] = rle_row(pb, srcrow,
+ si->zsize, si->xsize);
+ srcrow += info->pict.linesize[0];
+ }
+ }
+
+ url_fseek(pb, 512, SEEK_SET);
+
+ /* write offset table */
+ for (i = 0; i < (si->ysize * si->zsize); i++) {
+ put_be32(pb, offsettab[i]);
+ }
+
+ /* write length table */
+ for (i = 0; i < (si->ysize * si->zsize); i++) {
+ put_be32(pb, lengthtab[i]);
+ }
+
+ put_flush_packet(pb);
+
+ av_free(lengthtab);
+ av_free(offsettab);
+
+ return 0;
+}
+#endif // CONFIG_ENCODERS
+
+AVImageFormat sgi_image_format = {
+ "sgi",
+ "sgi,rgb,rgba,bw",
+ sgi_probe,
+ sgi_read,
+ (1 << PIX_FMT_GRAY8) | (1 << PIX_FMT_RGB24) | (1 << PIX_FMT_RGBA32),
+#ifdef CONFIG_ENCODERS
+ sgi_write,
+#else
+ NULL,
+#endif // CONFIG_ENCODERS
+};